<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Arik</title>
    <description>The latest articles on Forem by Arik (@acoh3n).</description>
    <link>https://forem.com/acoh3n</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F74828%2F4a9403cb-2190-42db-944f-58cf655c1495.jpg</url>
      <title>Forem: Arik</title>
      <link>https://forem.com/acoh3n</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/acoh3n"/>
    <language>en</language>
    <item>
      <title>You're NOT doing everything wrong</title>
      <dc:creator>Arik</dc:creator>
      <pubDate>Sat, 29 Nov 2025 17:53:41 +0000</pubDate>
      <link>https://forem.com/acoh3n/youre-not-doing-everything-wrong-4l5n</link>
      <guid>https://forem.com/acoh3n/youre-not-doing-everything-wrong-4l5n</guid>
      <description>&lt;p&gt;Walk into any engineering community online and you’ll quickly find yourself surrounded by old-time gunslingers shooting well-meaning advice at you: "Stop writing classes like that.", "Don't over-abstract", "Stop putting business logic in your controllers." and on and on. Just search the keyword "stop" on this site and you'll see what I'm talking about.&lt;/p&gt;

&lt;p&gt;The advice is usually correct. Technically. But it feels a lot like a virtuoso guitarist watching a beginner strum their first G chord and saying, "Actually, you’re holding that completely wrong. Also your timing is off, your pick angle is inefficient, and you're muting half the strings." That's not helpful to anyone.&lt;/p&gt;

&lt;p&gt;The truth is, every single one of those senior engineers wrote code that would make them cringe today. They shipped bugs. They nested callbacks eight levels deep. They used global variables without batting an eyelash. But they also learned a lot of valuable lessons first-hand.&lt;/p&gt;

&lt;p&gt;Of course they don't want others to make these same mistakes but unfortunately that's not how this works. You can't tell a baby to get up and start walking and "learn from you". Good engineering requires balancing an overwhelming amount of variables, each of which needs to be &lt;strong&gt;mastered&lt;/strong&gt; separately.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 10,000 hour rule
&lt;/h2&gt;

&lt;p&gt;It's tempting to think there's a shortcut—a book, a bootcamp, or a YouTube video that will transform your engineering skills overnight. But as Peter Norvig, director of research at Google, pointed out in his classic essay &lt;a href="https://www.norvig.com/21-days.html" rel="noopener noreferrer"&gt;Teach Yourself Programming in Ten Years&lt;/a&gt;, expertise isn't a weekend project. He warns against the "Teach Yourself (X Language) in 24 Hours" books by noting that while you might pick up superficial syntax in a day, writing meaningful programs, debugging in the wild, and grokking an ecosystem takes deliberate practice over a decade.&lt;/p&gt;

&lt;p&gt;Norvig draws on research from psychologists like Anders Ericsson, who popularized the "10,000-hour rule": mastery in fields like chess, music, or programming demands about 10 years of focused effort—roughly 10 to 20 hours a week of pushing your limits, getting feedback, and iterating on errors. Even geniuses like Mozart who was a musical prodigy at age 4, took 13 more years before he began to produce world-class music. The Beatles? A solid decade of small-club gigs before Sgt. Pepper's.&lt;/p&gt;

&lt;p&gt;The 10,000-hour figure isn’t magic (Ericsson himself later clarified it’s an average, not a universal law), but the core insight stands: real skill is built in the muscles and intuition, not dogma. You don’t truly understand why eight levels of nested callbacks are painful until you’ve personally lived through the day when the innermost one throws and you spend six hours unraveling the stack in your head. You don’t feel the cost of an over-abstracted "service layer" until you're the one onboarding a new teammate number seven who can’t find where the actual business rule lives. These lessons have to hurt a little, or they don’t stick.&lt;/p&gt;

&lt;p&gt;That's why the well-meaning "stop doing X" comments so often bounce off. The junior isn't being stubborn, they just lack the scar tissue required to feel the warning signs yet. Telling them "don’t prematurely optimize your code" is like telling a teenager "don’t fall in love with someone who's bad for you." The advice is correct, but it’s useless until life supplies the missing context.&lt;/p&gt;

&lt;p&gt;In programming terms, this means your first few thousand hours will be messy. You'll write inefficient loops, ignore edge cases, and probably invent your own wheel. But that's the point: those cringe-worthy commits are your deliberate practice. The solution? Do it anyway. Build large projects, read other people's code, refine. Rinse, repeat. Books help, but nothing beats building something that breaks—and fixing it yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Imitate the greats
&lt;/h2&gt;

&lt;p&gt;One of the fastest ways to compress those 10,000 hours is to stand on the shoulders of past giants. Every painter in art school spends months copying the old masters stroke-for-stroke before they’re allowed to "express themselves." Musicians transcribe solos note-for-note. Writers literally re-type entire novels by their heroes.&lt;/p&gt;

&lt;p&gt;Programmers almost never do this, and it’s mind-boggling.&lt;/p&gt;

&lt;p&gt;You will learn more in one week of carefully re-implementing a well-written open-source project than you will in six months of reading blog posts titled "10 Clean Code Principles You’re Probably Breaking."&lt;/p&gt;

&lt;p&gt;Pick something small but legendary. If you need ideas check out this &lt;a href="https://github.com/codecrafters-io/build-your-own-x" rel="noopener noreferrer"&gt;Github repo&lt;/a&gt;. Not because you're going to ship your own Redis tomorrow, but because the act of re-creating it forces you to confront thousands of tiny decisions that the original authors already solved elegantly. And more importantly, you'll have a benchmark against which you can compare your work to.&lt;/p&gt;

&lt;h2&gt;
  
  
  But what about AI?
&lt;/h2&gt;

&lt;p&gt;OK, elephant in the room. You’re being told from every corner that AI is the new 10,000-hour cheat code. "Just describe the feature, and let Cursor/Claude/Grok spit out the code." And on the surface it sounds good: The CRUD API that used to take days to build, now can be done in twenty minutes.&lt;/p&gt;

&lt;p&gt;But here’s the quiet part nobody wants to say out loud: &lt;strong&gt;AI is an extremely powerful painkiller, not a cure&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It removes the immediate sting of "how the heck do I do this?", but it also numbs the very feedback loop that builds real skill. When the model writes a 400-line "service" that technically works, you feel productive. You get the dopamine hit of green tests and a merged PR. But you didn’t actually grow the muscle that recognizes why that 400-line file is a maintenance nightmare waiting to happen.&lt;/p&gt;

&lt;p&gt;There’s no lasting satisfaction in vibe coding. You're not going to remember that time Claude wrote you a perfect pagination helper six months from now. You will remember the weekend you fixed a race condition that drove you crazy for days. That pain lodged itself in your long-term memory along with the solution, and now your intuition quietly steers you away from foot-guns.&lt;/p&gt;

&lt;p&gt;None of this means you should swear off AI. I use it every day. It’s an incredible pair-programming intern: fast, tireless, and full of ideas. But treat it like one. Review every line. Ask it "why did you do it this way?" and make it explain. When it suggests something that feels off, dig in—that discomfort is the scar tissue forming. &lt;/p&gt;

&lt;h2&gt;
  
  
  Your path to "Senior" status
&lt;/h2&gt;

&lt;p&gt;The senior engineer leaving the comment "Can we make this function pure, with no side effects?" isn’t lying. In five years you’ll probably agree with them completely, and you might even leave the exact same comment on someone else's PR. That’s not hypocrisy, that’s growth.&lt;/p&gt;

&lt;p&gt;You’re just doing what every great engineer before you did: writing the bad code that's required before you can write the good code.&lt;/p&gt;

&lt;p&gt;One day—probably years from now—you’ll open a pull request from some junior who's proudly over-abstracted the login flow into seventeen interfaces and a strategy factory. You'll feel that familiar urge to write "stop doing it like that."&lt;br&gt;
And if you took anything at all from this article, you’ll pause, smile, and write instead: "Let's get on a call. I want to share some ideas with you".&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>learningtocode</category>
      <category>deliberatepractice</category>
    </item>
    <item>
      <title>Inventing Blockchain: The tale of a frustrated programmer</title>
      <dc:creator>Arik</dc:creator>
      <pubDate>Sun, 26 Jan 2025 18:14:37 +0000</pubDate>
      <link>https://forem.com/acoh3n/inventing-blockchain-the-tale-of-a-frustrated-programmer-2o9f</link>
      <guid>https://forem.com/acoh3n/inventing-blockchain-the-tale-of-a-frustrated-programmer-2o9f</guid>
      <description>&lt;p&gt;Satoshi leaned back in his chair, staring at the blinking cursor on his laptop screen. His mother needed money—urgently. She lived halfway across the world, and her refrigerator had just kicked the bucket, spilling melted ice cream and spoiled milk onto the floor. "Just send me what you can, Satoshi," she’d said, her voice tight with worry. "I’ll figure it out."&lt;/p&gt;

&lt;p&gt;That was two days ago.&lt;/p&gt;

&lt;p&gt;Satoshi had done everything right—or so he thought. He’d logged into his bank account, initiated a transfer, and paid the exorbitant international fee without complaint. But the process wasn’t instant, not by a long shot. The bank had warned him it could take up to three business days to complete the transfer.&lt;/p&gt;

&lt;p&gt;He clenched his fists. Three days? What century was this? He could send an email to his mom in seconds. He could video call her instantly. But money? Money still crawled across borders like a letter in the mail.&lt;/p&gt;

&lt;p&gt;He’d even called customer service, hoping to speed things up. After navigating a labyrinth of hold music and robotic prompts, a weary-sounding representative informed him there was nothing to be done. "International transfers take time," she said flatly, as though the laws of physics themselves dictated it.&lt;/p&gt;

&lt;p&gt;Satoshi grumbled to himself as he closed his laptop. His mother was stuck waiting, and there was nothing he could do to help. It wasn’t just frustrating—it felt wrong. It felt unnecessary. "Why does it have to be this way?" he muttered.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with trust
&lt;/h2&gt;

&lt;p&gt;That night, Satoshi couldn’t stop thinking about it. He knew the transfer delay wasn’t about physics or technology—it was about &lt;strong&gt;trust&lt;/strong&gt;. His bank didn’t trust his mom’s bank. They relied on intermediaries, networks, and clearinghouses to vouch for each other. Every step of the process was a chain of people and institutions verifying the transaction. Each one took their cut, added their delay.&lt;/p&gt;

&lt;p&gt;Trust. The word hung heavy in Satoshi’s mind. Banks existed because people couldn’t trust each other directly with their money. But what if there was a way to eliminate the middleman? What if you could create a system where people could transact directly, without relying on trust at all?&lt;/p&gt;

&lt;p&gt;He scribbled the idea down in his notebook: &lt;strong&gt;"How to replace trust with math?"&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The first idea: a centralized transparent ledger
&lt;/h2&gt;

&lt;p&gt;By morning, Satoshi had a plan. If trust was the problem, transparency was the solution. What if there was a single, public ledger where anyone could log in and see every transaction? If the ledger was open for all to verify, no one could cheat.&lt;/p&gt;

&lt;p&gt;It didn’t take long for Satoshi to set up a basic website. He registered a domain, spun up a small server, and wrote the backend code. Transactions were stored in a simple database. The frontend was barebones but functional: a webpage where anyone could view the full list of transactions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;ledger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="c1"&gt;// Add a transaction to the ledger&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/add_transaction&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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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;const&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt; &lt;span class="o"&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;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;ledger&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;transaction&lt;/span&gt;&lt;span class="p"&gt;);&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="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// View the entire ledger&lt;/span&gt;
&lt;span class="nx"&gt;app&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/view_ledger&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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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;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;ledger&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;When a transaction was added, it would appear instantly on the public ledger. Satoshi imagined this would remove any suspicion or dishonesty. "If everyone can see everything," he thought, "then no one can cheat."&lt;/p&gt;

&lt;p&gt;He showed the prototype to his long time friend Taylor, who nodded appreciatively. “Okay, this is cool. But doesn’t this just make you the middleman?” she asked.&lt;/p&gt;

&lt;p&gt;Satoshi frowned. “What do you mean?”&lt;/p&gt;

&lt;p&gt;“Well,” Taylor said, gesturing at the screen, “you’re running the server, right? You’re the one people have to trust now.”&lt;/p&gt;

&lt;h2&gt;
  
  
  The realization
&lt;/h2&gt;

&lt;p&gt;Taylor’s words hung in the air. She was right. Satoshi’s transparent ledger was just a centralized system pretending to be trustless. Sure, anyone could view the transactions—but what if he decided to delete some? Or worse, alter them?&lt;/p&gt;

&lt;p&gt;Satoshi tried to argue with himself. "I wouldn’t do that," he muttered, pacing around the room. But the truth was unavoidable: the system was only as trustworthy as its operator. And that operator was him.&lt;/p&gt;

&lt;p&gt;“This isn’t the solution,” he said, slumping into his chair. “It’s just… another bank.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Decentralization and the struggle for trust
&lt;/h2&gt;

&lt;p&gt;Satoshi stared at his notebook, his frustration boiling over. The question gnawed at him: &lt;strong&gt;How do I get rid of myself?&lt;/strong&gt;. His centralized ledger had replaced one middleman with another—himself. If he wanted to create a truly trustless system, he’d have to eliminate his role entirely.&lt;/p&gt;

&lt;p&gt;But how?&lt;/p&gt;

&lt;p&gt;The question haunted him. He couldn’t sleep that night, his mind cycling through possibilities. By morning, the answer came to him: make the ledger decentralized.&lt;/p&gt;

&lt;h2&gt;
  
  
  The next idea: A decentralized ledger
&lt;/h2&gt;

&lt;p&gt;What if, instead of one server maintaining the ledger, everyone kept their own copy? Transactions would be broadcast to the entire network, and each participant would update their ledger independently. That way, no single person or entity would be in control.&lt;/p&gt;

&lt;p&gt;Satoshi excitedly sketched out the architecture. He imagined a network of peers, each running a lightweight program. Transactions would propagate through the network, and every participant would maintain their own version of the truth.&lt;/p&gt;

&lt;p&gt;Within hours, he was coding again, this time building a peer-to-peer prototype.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;net&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;net&lt;/span&gt;&lt;span class="dl"&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;ledger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="c1"&gt;// Peer-to-peer server&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;net&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;socket&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;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data&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="nx"&gt;data&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;const&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt; &lt;span class="o"&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;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nx"&gt;ledger&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;transaction&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Transaction added:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;transaction&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="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Peer listening on port 5000&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="c1"&gt;// Broadcast a transaction&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;broadcastTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;peers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;peers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;peer&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;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;net&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;peer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;peer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&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;transaction&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;He tested the system with Taylor, connecting their laptops over the network. Transactions flowed between their programs, and both of their ledgers updated in sync. It was a breakthrough.&lt;/p&gt;

&lt;p&gt;Or so it seemed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trust problem: forks and fraud
&lt;/h2&gt;

&lt;p&gt;Taylor, ever the skeptic, spotted the issue almost immediately. “Okay, so I send a transaction to you, and your ledger updates. But what happens if someone else sends me a conflicting transaction? Like if I spend the same $10 twice?”&lt;/p&gt;

&lt;p&gt;Satoshi frowned. “Well… everyone will see both transactions, and they’ll just figure out which one is valid.”&lt;/p&gt;

&lt;p&gt;Taylor raised an eyebrow. “How? What if different people update their ledgers in different orders? You could end up with two different versions of the truth.”&lt;/p&gt;

&lt;p&gt;Satoshi’s stomach sank. She was right. Without a way to enforce a single, agreed-upon history, the network could split into forks. Different participants might believe in different versions of the ledger. Worse, malicious actors could exploit the system, flooding it with fake transactions to confuse the network.&lt;/p&gt;

&lt;p&gt;He felt like he was back at square one. Decentralization had solved the problem of relying on a single middleman, but it had introduced a new issue: &lt;strong&gt;how do you get a group of untrustworthy participants to agree?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The spark of consensus
&lt;/h2&gt;

&lt;p&gt;Satoshi knew he needed a way for the network to converge on a single version of the ledger. He spent days researching distributed systems, reading about Byzantine fault tolerance and quorum protocols. The solutions were complex, often relying on trusted leaders or voting systems. But trust was exactly what he wanted to eliminate.&lt;/p&gt;

&lt;p&gt;The breakthrough came while reading an obscure article on cryptographic proofs. It described something called &lt;strong&gt;proof of work&lt;/strong&gt;, a technique originally used to deter email spam. The idea was simple but powerful: participants would perform a computationally expensive task to prove their commitment.&lt;/p&gt;

&lt;p&gt;Satoshi’s mind raced. What if transactions required proof of work? Instead of trusting votes or leaders, the network would trust the work itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Proof of Work
&lt;/h2&gt;

&lt;p&gt;The proof-of-work concept transformed Satoshi’s approach. Each participant in the network would compete to solve a cryptographic puzzle. The first to solve it would broadcast their solution, along with the new transactions, to the rest of the network. If the solution was valid -- which would be easy to verify -- everyone would add the new transactions to their ledger.&lt;/p&gt;

&lt;p&gt;He modified his code, implementing a simple proof-of-work algorithm. The puzzle was to find a number (a “nonce”) that, when combined with the transaction data and hashed, produced a hash starting with a specific number of zeros.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;crypto&lt;/span&gt;&lt;span class="dl"&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;difficulty&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;proofOfWork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transaction&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;nonce&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;nonce&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sha256&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="nf"&gt;update&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;transaction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hex&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;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;difficulty&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;nonce&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hash&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;
  
  
  Testing the system
&lt;/h2&gt;

&lt;p&gt;Taylor was impressed. “So, whoever solves the puzzle first gets to decide the next block of transactions?”&lt;/p&gt;

&lt;p&gt;“Exactly,” Satoshi said, smiling for the first time in days. “The puzzle is so hard to solve that no one can fake it. But once it’s solved, it’s easy for everyone else to verify.”&lt;/p&gt;

&lt;p&gt;They tested the system together, running separate instances of the program. The proof-of-work algorithm worked beautifully, ensuring that only one version of the ledger could advance at a time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inventing blockchain: the new problems
&lt;/h2&gt;

&lt;p&gt;For a fleeting moment, Satoshi felt like he had solved it. Proof of work seemed like the perfect solution. The puzzle was hard enough to prevent fraud, yet easy to verify once solved. Transactions flowed through the network, and everyone agreed on the ledger.&lt;/p&gt;

&lt;p&gt;But then the cracks began to show.&lt;/p&gt;

&lt;h2&gt;
  
  
  The energy Problem
&lt;/h2&gt;

&lt;p&gt;Taylor’s laptop hummed loudly, its fan spinning at full speed. “Is this supposed to be happening?” she asked, pointing at the temperature warning on her screen.&lt;/p&gt;

&lt;p&gt;Satoshi winced. He hadn’t thought much about the cost of computation. Proof of work relied on brute force, trying billions of combinations until it found the right one. As the difficulty increased, so did the energy required.&lt;/p&gt;

&lt;p&gt;“You’re burning through electricity just to process one transaction,” Taylor said, raising an eyebrow. “Imagine if thousands of people were doing this at the same time. The whole network would become a furnace.”&lt;/p&gt;

&lt;p&gt;Satoshi nodded grimly. He had optimized the code as much as possible, but proof of work was inherently resource-intensive. It was a price he hadn’t anticipated. “Maybe it’s worth it if it means we don’t need a middleman,” he said weakly.&lt;/p&gt;

&lt;p&gt;Taylor didn’t look convinced.&lt;/p&gt;

&lt;h2&gt;
  
  
  The monopoly problem
&lt;/h2&gt;

&lt;p&gt;Over the next few days, Satoshi expanded his tests to include more participants. At first, everything went smoothly. Friends joined the network, solving puzzles and adding transactions to their ledgers. But soon, another problem emerged: not everyone was solving puzzles at the same rate.&lt;/p&gt;

&lt;p&gt;Participants with faster computers—or, worse, specialized hardware—were completing proofs of work faster than everyone else. They dominated the network, consistently broadcasting their solutions first and claiming control over the ledger.&lt;/p&gt;

&lt;p&gt;“It’s just like the banks,” Taylor said, shaking her head. “The people with the most resources get to call the shots. It’s centralized all over again—just in a different way.”&lt;/p&gt;

&lt;p&gt;Satoshi felt the weight of her words. He had replaced trust in institutions with trust in computation, but the result was the same: inequality. The rich got richer, and the small players were pushed aside.&lt;/p&gt;

&lt;h2&gt;
  
  
  The incentive problem
&lt;/h2&gt;

&lt;p&gt;Even without the monopoly issue, Satoshi saw another flaw: why would anyone bother solving puzzles in the first place? Proof of work was costly. The energy required wasn’t free, and participants gained nothing tangible from their efforts.&lt;/p&gt;

&lt;p&gt;Taylor pointed this out during another late-night discussion. “If it costs so much to solve these puzzles, why would anyone do it? What’s in it for them?”&lt;/p&gt;

&lt;p&gt;Satoshi had no answer. He realized that without an incentive, the entire system would grind to a halt. Participants needed a reason to spend their resources cracking puzzles—something more compelling than altruism or ideology.&lt;/p&gt;

&lt;p&gt;It was a sobering realization. His system wasn’t sustainable. If he wanted it to work in the real world, he needed to introduce an economic element.&lt;/p&gt;

&lt;h2&gt;
  
  
  The birth of The Block
&lt;/h2&gt;

&lt;p&gt;Satoshi leaned back in his chair, rubbing his temples. The network needed a better structure, one that tied everything together. His eyes wandered to the ever-growing list of transactions on his screen. That’s when it hit him.&lt;/p&gt;

&lt;p&gt;“Why are we solving puzzles for individual transactions?” he muttered. “Why not group them?”&lt;/p&gt;

&lt;p&gt;If the system could bundle multiple transactions together into a single “block,” proof of work would only need to be done once for an entire group of transactions. This would immediately reduce the energy overhead—each puzzle would secure dozens or even hundreds of transactions, instead of just one.&lt;/p&gt;

&lt;p&gt;He sketched it out in his notebook. Each block would contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A list of transactions.&lt;/li&gt;
&lt;li&gt;A reference to the previous block’s proof (to chain them together).&lt;/li&gt;
&lt;li&gt;A proof of work for the current block.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result would be a chain of blocks—each securely linked to the one before it. Changing any block would invalidate the entire chain, making tampering nearly impossible. “It’s not just a ledger anymore,” he thought. “It’s… a blockchain.”&lt;/p&gt;

&lt;p&gt;But blocks didn’t just solve the energy problem—they opened the door to a solution for another pressing issue: &lt;strong&gt;incentives&lt;/strong&gt;. If participants competed to solve a block’s proof of work, the first to succeed could be rewarded for their effort. That reward could take the form of a new, native digital currency—coins created by the network itself.&lt;/p&gt;

&lt;p&gt;He scribbled furiously in his notebook: “Reward miners with cryptocurrency for creating new blocks.”&lt;/p&gt;

&lt;p&gt;The coins would serve as payment for the work miners did to secure the network, and they would have value because they were scarce and useful. Within the blockchain network, these coins could act as a medium of exchange, allowing participants to transact directly with one another for good and services.&lt;/p&gt;

&lt;p&gt;To prevent abuse, the reward system must ensure that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The reward is only issued when the block is mined and validated by the network.&lt;/li&gt;
&lt;li&gt;All participants independently verify the reward transaction as part of the validation process.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Mitigating monopolization
&lt;/h2&gt;

&lt;p&gt;The introduction of blocks didn’t just make the blockchain more efficient; it also helped reduce the risk of monopolization. Satoshi realized that smaller miners, unable to compete with powerful setups on their own, could band together by pooling their resources. In a mining pool, participants combined their computational power to increase their chances of solving a block’s proof-of-work puzzle. When the pool successfully mined a block, the reward was distributed proportionally among the contributors. Pooling allowed smaller miners to stay relevant in the network, ensuring they had a fair chance to earn rewards despite their limited hardware.&lt;/p&gt;

&lt;p&gt;At the same time, the architecture of the blockchain made monopolization through fraud prohibitively difficult. Because each block was cryptographically linked to the one before it, tampering with a single block wasn’t enough to rewrite history. Changing even one transaction in an old block would invalidate its hash and all subsequent blocks in the chain. An attacker would need to remine the altered block and every block after it. The computational cost of such an attack grew exponentially with the number of blocks in the chain, making the system effectively tamper-proof.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing the Blockchain
&lt;/h2&gt;

&lt;p&gt;Satoshi started by implementing the blockchain itself. Each block would store a set of transactions, a proof of work, and a reference to the previous block. This reference linked the blocks together, creating a chain. If someone tried to alter an earlier block, it would invalidate the entire chain because the cryptographic link would break.&lt;/p&gt;

&lt;p&gt;The first block, known as the “genesis block,” had no predecessor and was hardcoded into the system. Every subsequent block was mined by solving a proof-of-work puzzle, and its reference to the previous block’s proof ensured that the chain remained immutable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;crypto&lt;/span&gt;&lt;span class="dl"&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;blockchain&lt;/span&gt; &lt;span class="o"&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;rewardAmount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Create the genesis block&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createGenesisBlock&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="na"&gt;index&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="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&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="na"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="na"&gt;proof&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;previousHash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0&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;// Calculate the hash of a block&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;calculateHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;block&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;crypto&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sha256&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="nf"&gt;update&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;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nonce&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;previousHash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hex&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="c1"&gt;// Create a new block&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createBlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;previousHash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;difficulty&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;nonce&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&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;rewardTransaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Network&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Miner&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rewardAmount&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="c1"&gt;// Add the reward transaction to the transactions list&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blockTransactions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rewardTransaction&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;nonce&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sha256&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="nf"&gt;update&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;blockTransactions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;nonce&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;previousHash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hex&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;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;difficulty&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="na"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;blockchain&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="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&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="na"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;blockTransactions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;proof&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;previousHash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;nonce&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;// Validate a block&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validateBlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;previousBlock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;difficulty&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="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;previousHash&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;previousBlock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;proof&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="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Invalid link to previous block&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;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculateHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;block&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;hash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;difficulty&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="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Proof of work is invalid&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;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transactions&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="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;rewardAmount&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="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Invalid reward transaction&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="c1"&gt;// Initialize the blockchain with the genesis block&lt;/span&gt;
&lt;span class="nx"&gt;blockchain&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="nf"&gt;createGenesisBlock&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing the Blockchain
&lt;/h2&gt;

&lt;p&gt;Satoshi leaned back in his chair, watching the blockchain grow. Each block carried its own proof of work, a list of transactions, and the miner’s reward. But as Taylor reviewed the system, she raised a concern.&lt;/p&gt;

&lt;p&gt;“Wait,” she said, scrolling through the blockchain logs. “What’s stopping me from just giving myself a million coins in the reward transaction?”&lt;/p&gt;

&lt;p&gt;Satoshi smirked. “Go ahead. Try.”&lt;/p&gt;

&lt;p&gt;Taylor modified the code to include a reward of one million coins instead of the standard fifty. She mined a block and added it to her local chain. At first glance, the block looked valid—her version of the blockchain updated, and the oversized reward transaction showed up.&lt;/p&gt;

&lt;p&gt;But when Taylor’s chain attempted to sync with the network, the other nodes rejected her block. “Invalid block,” the logs reported. Taylor frowned. “Why didn’t it work?”&lt;/p&gt;

&lt;p&gt;Satoshi explained. “The reward transaction is just like any other transaction—it’s validated by the entire network. If the reward doesn’t follow the rules, the block is rejected. You can mine all the blocks you want, but no one else will accept them unless they’re valid.”&lt;/p&gt;

&lt;p&gt;She nodded, impressed. “So the network enforces fairness?”&lt;/p&gt;

&lt;p&gt;“Exactly,” Satoshi said. “No one—not even the miner—can cheat the system.”&lt;/p&gt;

&lt;h2&gt;
  
  
  A Vision for the future
&lt;/h2&gt;

&lt;p&gt;As the weeks turned into months, Satoshi refined the system, documenting the protocol in meticulous detail. He imagined a world where people could transact directly, where intermediaries weren’t needed to enforce trust. Where governments, corporations, and even individuals could build applications on top of the blockchain to empower people.&lt;/p&gt;

&lt;p&gt;It wasn’t just about money. The blockchain could track ownership, verify identities, manage contracts, and create entirely new forms of cooperation. Satoshi saw the possibilities stretching out before him, and for the first time in years, he felt hopeful about the world he lived in.&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>cryptocurrency</category>
      <category>story</category>
      <category>innovation</category>
    </item>
    <item>
      <title>Making binary search slower</title>
      <dc:creator>Arik</dc:creator>
      <pubDate>Sat, 18 Jan 2025 20:52:55 +0000</pubDate>
      <link>https://forem.com/acoh3n/making-binary-search-slower-5h97</link>
      <guid>https://forem.com/acoh3n/making-binary-search-slower-5h97</guid>
      <description>&lt;p&gt;Binary search is frequently praised as one of the most efficient algorithms for finding an element in a sorted dataset. It’s fast—blazingly fast—and its efficiency grows more apparent as the size of the search space increases. But how can we truly appreciate its speed in a world where computers perform millions of operations per second?&lt;/p&gt;

&lt;p&gt;Let’s flip the script: we’re going to &lt;strong&gt;intentionally slow down the algorithm&lt;/strong&gt; by adding a one-second delay to each iteration. This simple twist will help us feel the power of binary search and understand how its logarithmic efficiency scales with the size of the dataset.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is binary search?
&lt;/h2&gt;

&lt;p&gt;Before diving into the code, let’s quickly recap binary search. Given a sorted list, binary search divides the list in half at each step, checking whether the target value lies in the left or right half. This process continues until the target is found or the search space is reduced to zero.&lt;/p&gt;

&lt;p&gt;Here’s why it’s so efficient: with each step, the size of the search space is halved. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A list of 1,000 elements requires at most 10 comparisons.&lt;/li&gt;
&lt;li&gt;A list of 1 million elements? Just 20 comparisons.&lt;/li&gt;
&lt;li&gt;A list of 1 billion elements? 30 comparisons.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The twist: slowing it down
&lt;/h2&gt;

&lt;p&gt;To make the efficiency of binary search tangible, we’ll modify the algorithm by adding a one-second delay to each iteration. This way, the time taken will scale directly with the number of steps the algorithm performs. Watching the algorithm process datasets of different sizes will give us an intuitive understanding of how it scales.&lt;/p&gt;

&lt;p&gt;Here’s the implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;binary_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Performs a binary search with a 1-second delay per iteration.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;low&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&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="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;  &lt;span class="c1"&gt;# Track the number of iterations
&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;low&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;low&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Iteration &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;iterations&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: Checking index &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; (value: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Artificial delay to simulate time passing
&lt;/span&gt;        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Found &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; at index &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; after &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;iterations&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; seconds.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;low&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;high&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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;target&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; not found after &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;iterations&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; seconds.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="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;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Parse command-line arguments
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;3&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;Usage: python binary_search.py &amp;lt;array_size&amp;gt; &amp;lt;target_value&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&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;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;array_size&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;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&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;target&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;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&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;except&lt;/span&gt; &lt;span class="nb"&gt;ValueError&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;Both array_size and target_value must be integers.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&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;# Generate the sorted array
&lt;/span&gt;    &lt;span class="n"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&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;array_size&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Starting binary search for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; in an array of size &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;array_size&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&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="c1"&gt;# Run the binary search
&lt;/span&gt;    &lt;span class="nf"&gt;binary_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How to run the script
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python binary_search.py &amp;lt;array_size&amp;gt; &amp;lt;target_value&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Examples
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;10 elements&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;% python3 script.py 10 4
Starting binary search &lt;span class="k"&gt;for &lt;/span&gt;4 &lt;span class="k"&gt;in &lt;/span&gt;an array of size 10...

Iteration 1: Checking index 4 &lt;span class="o"&gt;(&lt;/span&gt;value: 4&lt;span class="o"&gt;)&lt;/span&gt;
Found 4 at index 4 after 1 seconds.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;1000 elements&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;% python3 script.py 1000 572
Starting binary search &lt;span class="k"&gt;for &lt;/span&gt;572 &lt;span class="k"&gt;in &lt;/span&gt;an array of size 1000...

Iteration 1: Checking index 499 &lt;span class="o"&gt;(&lt;/span&gt;value: 499&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 2: Checking index 749 &lt;span class="o"&gt;(&lt;/span&gt;value: 749&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 3: Checking index 624 &lt;span class="o"&gt;(&lt;/span&gt;value: 624&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 4: Checking index 561 &lt;span class="o"&gt;(&lt;/span&gt;value: 561&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 5: Checking index 592 &lt;span class="o"&gt;(&lt;/span&gt;value: 592&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 6: Checking index 576 &lt;span class="o"&gt;(&lt;/span&gt;value: 576&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 7: Checking index 568 &lt;span class="o"&gt;(&lt;/span&gt;value: 568&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 8: Checking index 572 &lt;span class="o"&gt;(&lt;/span&gt;value: 572&lt;span class="o"&gt;)&lt;/span&gt;
Found 572 at index 572 after 8 seconds.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;1 million elements&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;% python3 script.py 1000000 78246
Starting binary search &lt;span class="k"&gt;for &lt;/span&gt;78246 &lt;span class="k"&gt;in &lt;/span&gt;an array of size 1000000...

Iteration 1: Checking index 499999 &lt;span class="o"&gt;(&lt;/span&gt;value: 499999&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 2: Checking index 249999 &lt;span class="o"&gt;(&lt;/span&gt;value: 249999&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 3: Checking index 124999 &lt;span class="o"&gt;(&lt;/span&gt;value: 124999&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 4: Checking index 62499 &lt;span class="o"&gt;(&lt;/span&gt;value: 62499&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 5: Checking index 93749 &lt;span class="o"&gt;(&lt;/span&gt;value: 93749&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 6: Checking index 78124 &lt;span class="o"&gt;(&lt;/span&gt;value: 78124&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 7: Checking index 85936 &lt;span class="o"&gt;(&lt;/span&gt;value: 85936&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 8: Checking index 82030 &lt;span class="o"&gt;(&lt;/span&gt;value: 82030&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 9: Checking index 80077 &lt;span class="o"&gt;(&lt;/span&gt;value: 80077&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 10: Checking index 79100 &lt;span class="o"&gt;(&lt;/span&gt;value: 79100&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 11: Checking index 78612 &lt;span class="o"&gt;(&lt;/span&gt;value: 78612&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 12: Checking index 78368 &lt;span class="o"&gt;(&lt;/span&gt;value: 78368&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 13: Checking index 78246 &lt;span class="o"&gt;(&lt;/span&gt;value: 78246&lt;span class="o"&gt;)&lt;/span&gt;
Found 78246 at index 78246 after 13 seconds.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;1 billion elements&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;% python3 script.py 1000000000 708246
Starting binary search &lt;span class="k"&gt;for &lt;/span&gt;708246 &lt;span class="k"&gt;in &lt;/span&gt;an array of size 1000000000...

Iteration 1: Checking index 499999999 &lt;span class="o"&gt;(&lt;/span&gt;value: 499999999&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 2: Checking index 249999999 &lt;span class="o"&gt;(&lt;/span&gt;value: 249999999&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 3: Checking index 124999999 &lt;span class="o"&gt;(&lt;/span&gt;value: 124999999&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 4: Checking index 62499999 &lt;span class="o"&gt;(&lt;/span&gt;value: 62499999&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 5: Checking index 31249999 &lt;span class="o"&gt;(&lt;/span&gt;value: 31249999&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 6: Checking index 15624999 &lt;span class="o"&gt;(&lt;/span&gt;value: 15624999&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 7: Checking index 7812499 &lt;span class="o"&gt;(&lt;/span&gt;value: 7812499&lt;span class="o"&gt;)&lt;/span&gt;
...
Iteration 25: Checking index 708248 &lt;span class="o"&gt;(&lt;/span&gt;value: 708248&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 26: Checking index 708233 &lt;span class="o"&gt;(&lt;/span&gt;value: 708233&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 27: Checking index 708240 &lt;span class="o"&gt;(&lt;/span&gt;value: 708240&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 28: Checking index 708244 &lt;span class="o"&gt;(&lt;/span&gt;value: 708244&lt;span class="o"&gt;)&lt;/span&gt;
Iteration 29: Checking index 708246 &lt;span class="o"&gt;(&lt;/span&gt;value: 708246&lt;span class="o"&gt;)&lt;/span&gt;
Found 708246 at index 708246 after 29 seconds.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;This experiment (hopefully) demonstrates the elegance of binary search. By slowing it down, we make its logarithmic behavior easy to observe and appreciate. No matter how large the dataset, the number of steps grows at a manageable rate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;Run the code, tweak the dataset sizes, and experiment with different target values. If you’re teaching others about algorithms or learning them yourself, this slowed-down version of binary search might be a good way to to give them a "feel" for it.&lt;/p&gt;

&lt;p&gt;What are your thoughts on this approach? Do you have any other creative twists for understanding algorithms? Share your ideas in the comments below!&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>computerscience</category>
      <category>binarysearch</category>
    </item>
    <item>
      <title>Building a webhook tester from scratch</title>
      <dc:creator>Arik</dc:creator>
      <pubDate>Wed, 01 Jan 2025 20:07:00 +0000</pubDate>
      <link>https://forem.com/acoh3n/building-a-webhook-tester-from-scratch-34a8</link>
      <guid>https://forem.com/acoh3n/building-a-webhook-tester-from-scratch-34a8</guid>
      <description>&lt;p&gt;Every now and then I find myself in need of a quick way to debug and test webhooks without the hassle of setting up an entire server. Whether it's validating a third-party API integration, troubleshooting event payloads, or simply experimenting with custom webhook workflows.&lt;/p&gt;

&lt;p&gt;While there are plenty of solutions out there designed to test webhooks, they often come with significant limitations. Many of these tools are not self-hostable (or are difficult to install), they have stringent request limits (unless you’re willing to pay), they feel too complex, and they often store data on their servers, raising concerns about privacy and security, especially when I'm dealing with sensitive payloads.&lt;/p&gt;

&lt;p&gt;So, I decided to build my own webhook tester with the following requirements: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simple&lt;/strong&gt; - No paywalls, sign-up or having to jump through a bunch of hoops to create a webhook.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Privacy-first&lt;/strong&gt; - Nothing is stored on the servers. Requests go from the client to the browser that created the webhook.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Self-hostable&lt;/strong&gt; - Easy to install without having to setup a database or other pieces of infrastructure. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wirehook
&lt;/h2&gt;

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

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

&lt;p&gt;Here’s how &lt;a href="https://wirehook.net" rel="noopener noreferrer"&gt;Wirehook&lt;/a&gt; looks in action. The interface is clean and straightforward: you get a unique URL to use as your webhook endpoint, and any incoming requests are displayed in real-time for you to view and analyze. And that's basically it.&lt;/p&gt;

&lt;p&gt;If you'd  like to run Wirehook locally on your machine (or on your servers), all you need is Docker installed. Once that's ready, just run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:3000 runabol/wirehook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will spin up Wirehook on your local machine, accessible at &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;. From there, you can create and test webhook endpoints just like you would with the hosted version.&lt;/p&gt;

&lt;p&gt;Wirehook was built entirely using Next.js to keep it simple and self-contained. If you’re curious to see how it works or want to get involved, the full source code is available on &lt;a href="https://github.com/runabol/wirehook" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>webhooks</category>
      <category>nextjs</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Building scalable ML workflows</title>
      <dc:creator>Arik</dc:creator>
      <pubDate>Sun, 22 Dec 2024 14:56:47 +0000</pubDate>
      <link>https://forem.com/acoh3n/building-scalable-ml-workflows-4f0k</link>
      <guid>https://forem.com/acoh3n/building-scalable-ml-workflows-4f0k</guid>
      <description>&lt;p&gt;A little while back, I &lt;a href="https://dev.to/acoh3n/building-a-distributed-workflow-engine-from-scratch-22kl"&gt;wrote a post&lt;/a&gt; introducing &lt;a href="https://github.com/runabol/tork" rel="noopener noreferrer"&gt;Tork&lt;/a&gt;, an open-source project I've been developing. In a nutshell, Tork is a general-purpose, distributed workflow engine suitable for various workloads. At my work, we primarily use it for CPU/GPU-heavy tasks such as processing digital assets (3D, videos, images etc.), as well as our CI/CD tool for our internal PaaS. &lt;/p&gt;

&lt;p&gt;Recently, I've been thinking about how Tork could potentially be leveraged to run machine learning type workloads. I was particularly inspired by the &lt;a href="https://ollama.com/" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt; project and wanted to see if I can do something similar, but using plain old Docker images rather than Ollama's &lt;a href="https://github.com/ollama/ollama/blob/main/docs/modelfile.md" rel="noopener noreferrer"&gt;Modelfile&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Given that ML workloads often consist of distinct, interdependent stages—such as data preprocessing, feature extraction, model training, and inference—it’s crucial to have an engine that can orchestrate these steps. These stages frequently require different types of compute resources (e.g., CPUs for preprocessing, GPUs for training) and can benefit greatly from parallelization. &lt;/p&gt;

&lt;p&gt;Moreover, resiliency is a critical requirement when running machine learning workflows. Interruptions, whether due to hardware failures, network issues, or resource constraints, can result in significant setbacks, especially for long-running processes like model training.&lt;/p&gt;

&lt;p&gt;These requirements are very similar to my other non-ML workloads, so I decided to put my all my theories to the test and see what it would take to execute a simple ML workflow on Tork. &lt;/p&gt;

&lt;h2&gt;
  
  
  The experiment
&lt;/h2&gt;

&lt;p&gt;For this first experiment, let's try to execute a simple sentiment analysis inference task:&lt;/p&gt;

&lt;p&gt;Download the latest &lt;a href="https://github.com/runabol/tork/releases/tag/v0.1.109" rel="noopener noreferrer"&gt;Tork binary&lt;/a&gt; and untar it.&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="nb"&gt;tar &lt;/span&gt;xvzf tork_0.1.109_darwin_arm64.tgz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start Tork in &lt;code&gt;standalone&lt;/code&gt; mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./tork run standalone
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If all goes well, you should something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;...
10:36PM INF Coordinator listening on http://localhost:8000
...

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we need to build a docker image that contains the model and the necessary inference script. Tork tasks typically execute within a Docker container.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;inference.py&lt;/code&gt;&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;transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AutoTokenizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AutoModelForSequenceClassification&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="n"&gt;MODEL_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MODEL_NAME&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_model_and_tokenizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model_name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;tokenizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoTokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoModelForSequenceClassification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model_name&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;tokenizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;predict_sentiment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;inputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;return_tensors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;truncation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;no_grad&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&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;predictions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;functional&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;softmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&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;predicted_label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;argmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;predictions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&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="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;confidence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;predictions&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;predicted_label&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;item&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;predicted_label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;confidence&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load_model_and_tokenizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MODEL_NAME&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;INPUT_TEXT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;confidence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;predict_sentiment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sentiment_map&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Negative&lt;/span&gt;&lt;span class="sh"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Positive&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;sentiment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sentiment_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;label&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;sentiment&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Dockerfile&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM huggingface/transformers-pytorch-cpu:latest

WORKDIR /app

COPY inference.py .

# Pre-load the model during image build
RUN python3 -c "from transformers import AutoTokenizer, AutoModelForSequenceClassification; AutoTokenizer.from_pretrained('distilbert-base-uncased-finetuned-sst-2-english'); AutoModelForSequenceClassification.from_pretrained('distilbert-base-uncased-finetuned-sst-2-english')"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; sentiment-analysis &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, let's create the Tork job to run the inference.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sentiment.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Sentiment analysis example&lt;/span&gt;
&lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;input_text&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Today is a lovely day&lt;/span&gt;
  &lt;span class="na"&gt;model_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;distilbert-base-uncased-finetuned-sst-2-english&lt;/span&gt;
&lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{trim(tasks.sentimentResult)}}"&lt;/span&gt;
&lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run sentiment analysis&lt;/span&gt;
    &lt;span class="na"&gt;var&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sentimentResult&lt;/span&gt;
    &lt;span class="c1"&gt;# the image we created in the previous step, &lt;/span&gt;
    &lt;span class="c1"&gt;# but can be any image available from Docker hub&lt;/span&gt;
    &lt;span class="c1"&gt;# or any other image registry&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sentiment-analysis:latest&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;python3 inference.py &amp;gt; $TORK_OUTPUT&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;INPUT_TEXT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{inputs.input_text}}"&lt;/span&gt;
      &lt;span class="na"&gt;MODEL_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{inputs.model_name}}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Submit the job. Tork jobs execute asynchronously. Once a job is submitted you get back a job ID to track its progress:&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="nv"&gt;JOB_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"content-type:text/yaml"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-binary&lt;/span&gt; @sentiment.yaml &lt;span class="se"&gt;\&lt;/span&gt;
  http://localhost:8000/jobs | jq &lt;span class="nt"&gt;-r&lt;/span&gt; .id&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Poll the job's status and wait for it to complete:&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="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do 
  &lt;/span&gt;&lt;span class="nv"&gt;state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://localhost:8000/jobs/&lt;span class="nv"&gt;$JOB_ID&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; .state&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Status: &lt;/span&gt;&lt;span class="nv"&gt;$state&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$state&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"COMPLETED"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
     &lt;span class="nb"&gt;break 
  &lt;/span&gt;&lt;span class="k"&gt;fi 
  &lt;/span&gt;&lt;span class="nb"&gt;sleep &lt;/span&gt;1
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inspect the job results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://localhost:8000/jobs/&lt;span class="nv"&gt;$JOB_ID&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; .result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Positive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try changing the &lt;code&gt;input_text&lt;/code&gt; in &lt;code&gt;sentiment.yaml&lt;/code&gt; and re-submit the job for different results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;Now that I got this basic proof of concept working on my machine I need to push that Docker image to a Docker registry so it is available for any Tork workers on my production cluster. But this seems like a viable approach.&lt;/p&gt;

&lt;p&gt;The code for this article can be found on &lt;a href="https://github.com/runabol/tork-demo-ml" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you're interested in learning more about Tork:&lt;/p&gt;

&lt;p&gt;Documentation: &lt;a href="https://www.tork.run" rel="noopener noreferrer"&gt;https://www.tork.run&lt;/a&gt;&lt;br&gt;
Backend: &lt;a href="https://github.com/runabol/tork" rel="noopener noreferrer"&gt;https://github.com/runabol/tork&lt;/a&gt;&lt;br&gt;
Web UI: &lt;a href="https://github.com/runabol/tork-web" rel="noopener noreferrer"&gt;https://github.com/runabol/tork-web&lt;/a&gt;&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>workflowengine</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>What is your Why?</title>
      <dc:creator>Arik</dc:creator>
      <pubDate>Wed, 13 Sep 2023 02:06:27 +0000</pubDate>
      <link>https://forem.com/acoh3n/what-is-your-why-j9b</link>
      <guid>https://forem.com/acoh3n/what-is-your-why-j9b</guid>
      <description>&lt;p&gt;I believe we all entered the field of programming for various reasons. It could be to earn a living, pursue a sought-after career, or simply because we love building stuff. Whatever the reason, we're here.&lt;/p&gt;

&lt;p&gt;However, if I'm being perfectly honest, while all these are good reasons, none would provide me with more than the bare minimum level of happiness at what I do almost every day for many hours.&lt;/p&gt;

&lt;p&gt;Yet, while I had my fair share of miserable days on the job like everyone else, more often than not, I am truly eager to do my thing at work. &lt;/p&gt;

&lt;p&gt;So today, while I was running, I found myself in a bit of an introspective mood and wondered what is my personal Why? Why do I still love programming so much after all these years. &lt;/p&gt;

&lt;p&gt;I always knew it had something to do with people. Seeing someone using something I wrote and maybe even liking it never ceases to give me a kick. But I felt there was a deeper desire. &lt;/p&gt;

&lt;p&gt;After a little back and forth with myself I reduced it to something that felt really true for me: &lt;strong&gt;to reduce the suffering of someone else&lt;/strong&gt;. Okay, I know it sounds a bit overly dramatic, but hear me out here for a minute. &lt;/p&gt;

&lt;p&gt;Our profession is riddled with sharp objects we all occasionally bump into. People much smarter than myself say that it takes &lt;a href="https://norvig.com/21-days.html" rel="noopener noreferrer"&gt;a very long&lt;/a&gt; time to even begin to master it, there is formidable math and sophisticated algorithms lurking at every corner, then there are new languages, tools, frameworks and paradigms jumping on us every other day that threaten to undermine everything we've learned for the past however many years. &lt;/p&gt;

&lt;p&gt;So when I get to brighten someone's day through my work in even the smallest way, damn it it feels good. &lt;/p&gt;

&lt;p&gt;It could be a user that with the help of something I wrote suddenly feels much more productive, or it could be as "small" as assisting a colleague by showing them how to use some tool that I take for granted, but is life-changing for them. &lt;/p&gt;

&lt;p&gt;That's why I relish at the opportunity to spend that extra hour at making my API just a tiny bit simpler, or clean up and refactor some messy code, or write that extra page of documentation or test. Because someone (including myself) will experience just a tiny bit less frustration and pain down the road when they try to use it. &lt;/p&gt;

&lt;p&gt;And whenever I get to see it first hand it gives me the energy to wake up the next day and do it all over again. &lt;/p&gt;

&lt;p&gt;So now I'd like to invite you to find your personal Why, and to please share it with us.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>musings</category>
    </item>
    <item>
      <title>Let's build a code execution engine</title>
      <dc:creator>Arik</dc:creator>
      <pubDate>Sun, 10 Sep 2023 23:38:40 +0000</pubDate>
      <link>https://forem.com/acoh3n/lets-build-a-code-execution-engine-4kgi</link>
      <guid>https://forem.com/acoh3n/lets-build-a-code-execution-engine-4kgi</guid>
      <description>&lt;p&gt;Have you ever wondered what happens behind the scenes when you hit "Run" on a code snippet in online development environments like &lt;a href="https://go.dev/play/" rel="noopener noreferrer"&gt;Go Playground&lt;/a&gt; or &lt;a href="https://onecompiler.com" rel="noopener noreferrer"&gt;OneCompiler&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;By following along, at the end of this post, you will have the front-end and backend for a very bare-bones implementation that resembles something like this:&lt;/p&gt;

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

&lt;p&gt;If you just want to see the code, you can find it &lt;a href="https://github.com/runabol/code-execution-demo" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It's important to note that while skeletal, the implementation  is by no means a "toy". We will address the most important considerations for building the core requirement of such a platform. Namely:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt; - we are letting users execute arbitrary code on our servers so we need a way to isolate the code execution in order to limit the possibility for abuse as much as possible.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt; - We need a way to scale our system as the number of users grow.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Limits&lt;/strong&gt; - We want to limit the amount of resources we are allocating for a given code execution so it doesn't tax our servers as well as hurt other users' experience. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What are we going to use
&lt;/h2&gt;

&lt;p&gt;In order to address all the considerations mentioned above, we are going to use &lt;a href="https://github.com/runabol/tork" rel="noopener noreferrer"&gt;Tork&lt;/a&gt; to do all the heavy lifting for us.&lt;/p&gt;

&lt;p&gt;In a nutshell, Tork is a general purpose, distributed workflow engine that I've been working on for the &lt;a href="https://dev.to/acoh3n/building-a-distributed-workflow-engine-from-scratch-22kl"&gt;past couple of months&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It uses Docker containers for the execution of workflow tasks which addresses point #1 and point #3 for us - we'll see exactly how in a minute. &lt;/p&gt;

&lt;p&gt;It also supports a distributed setup to scale task processing to an arbitrary number of worker nodes which addresses point #2.&lt;/p&gt;

&lt;p&gt;There are two ways we can go about this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.tork.run/installation" rel="noopener noreferrer"&gt;Download&lt;/a&gt; and install the vanilla Tork and write a new thin API service that will sit between the client and Tork -- because we don't necessarily want to expose Tork's native API to them in order to have tight control over which parameters are sent to Tork. The advantage with this approach is that I can write my "middleware" server in a language of my choice.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.tork.run/customize" rel="noopener noreferrer"&gt;Extend Tork&lt;/a&gt; to expose our custom API endpoint and disable all other endpoints. This requires knowledge of Go programming.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For the purposes of this demo I'll be going with option #2.&lt;/p&gt;

&lt;h2&gt;
  
  
  OK, let's write some code
&lt;/h2&gt;

&lt;p&gt;You'll need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Docker installed on the machine that you're running the demo on.&lt;/li&gt;
&lt;li&gt;Golang &amp;gt;= 1.19+&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Create a new directory for the project:&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="nb"&gt;mkdir &lt;/span&gt;code-execution-demo
&lt;span class="nb"&gt;cd &lt;/span&gt;code-execution-demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Initialize the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go mod init example.com/code-execution-demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Get the Tork dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get github.com/runabol/tork
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a &lt;code&gt;main.go&lt;/code&gt; file at the root of the project with the minimum boilerplate necessary to start Tork:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/runabol/tork/cli"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/runabol/tork/conf"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c"&gt;// Load the Tork config file (if exists) &lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoadConfig&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="c"&gt;// Start the Tork CLI&lt;/span&gt;
   &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cli&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&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;Start Tork:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go run main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If all goes well, you should see something like this:&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="o"&gt;||&lt;/span&gt;       &lt;span class="o"&gt;||&lt;/span&gt;    _ |  |   | | |
|_     _||   _   &lt;span class="o"&gt;||&lt;/span&gt;   | &lt;span class="o"&gt;||&lt;/span&gt;  |   |_| |
  |   |  |  | |  &lt;span class="o"&gt;||&lt;/span&gt;   |_||_ |      _|
  |   |  |  |_|  &lt;span class="o"&gt;||&lt;/span&gt;    __  &lt;span class="o"&gt;||&lt;/span&gt;     |_ 
  |   |  |       &lt;span class="o"&gt;||&lt;/span&gt;   |  | &lt;span class="o"&gt;||&lt;/span&gt;    _  |
  |___|  |_______||___|  |_||___| |_|
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's use the &lt;code&gt;RegisterEndpoint&lt;/code&gt; hook to register our custom endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/runabol/tork/cli"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/runabol/tork/conf"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/runabol/tork/middleware/web"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// removed for brevity&lt;/span&gt;

    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RegisterEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MethodPost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/execute"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// removed for brevity&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&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;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"OK"&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;Start Tork in &lt;code&gt;standalone&lt;/code&gt; (not distributed) mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go run main.go run standalone
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Call the new endpoint from another terminal window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8000/execute
OK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So far so good.&lt;/p&gt;

&lt;p&gt;Let's assume the client is going to send us the following JSON object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"language"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"python|bash|go|etc."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"the source code to execute"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's write a struct that we can bind these values to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ExecRequest&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Code&lt;/span&gt;     &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"code"`&lt;/span&gt;
    &lt;span class="n"&gt;Language&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"language"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ExecRequest&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&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="no"&gt;nil&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;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;req&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;At this point we just echo the request back to the user. But it's a good stepping stone to make sure the binding logic works. Let's try it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"content-type:application/json"&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"language":"bash","code":"echo hello world"}'&lt;/span&gt; http://localhost:8000/execute

&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"code"&lt;/span&gt;:&lt;span class="s2"&gt;"echo hello world"&lt;/span&gt;,&lt;span class="s2"&gt;"language"&lt;/span&gt;:&lt;span class="s2"&gt;"bash"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OK, next we need to convert the request to a Tork task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;buildTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;er&lt;/span&gt; &lt;span class="n"&gt;ExecRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;

        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;er&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Language&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&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="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"require: language"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"python"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"python:3"&lt;/span&gt;
                &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"script.py"&lt;/span&gt;
                &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"python script.py &amp;gt; $TORK_OUTPUT"&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"go"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"golang:1.19"&lt;/span&gt;
                &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"main.go"&lt;/span&gt;
                &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"go run main.go &amp;gt; $TORK_OUTPUT"&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"bash"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"alpine:3.18.3"&lt;/span&gt;
                &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"script"&lt;/span&gt;
                &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"sh ./script &amp;gt; $TORK_OUTPUT"&lt;/span&gt;
        &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&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="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"unknown language: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;er&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Language&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;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="s"&gt;"execute code"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Files&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;er&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Code&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="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we are doing three things here essentially: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Map the &lt;code&gt;language&lt;/code&gt; field to a Docker image.&lt;/li&gt;
&lt;li&gt;Write the &lt;code&gt;code&lt;/code&gt; to an appropriate file in the container depending on the &lt;code&gt;language&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run the necessary command to execute the code in the container.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's use it in our handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;buildTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&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="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, let's submit the job:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Job&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;"code execution"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;Tasks&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;   

&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SubmitJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="n"&gt;input&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"job %s submitted!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's try to run our updated handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go run main.go run standalone
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X POST -H "content-type:application/json" -d '{"language":"bash","code":"echo hello world"}' http://localhost:8000/execute
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If all goes well, you should see something like this in the logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;job 5488620e9bc34e09b6ec3677ea28a067 submitted!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we want to get the execution output so we can return it to the client. But since Tork operates asynchronously we need a way to tell Tork to let us know what the job is done (or failed).&lt;/p&gt;

&lt;p&gt;This is where &lt;code&gt;JobListener&lt;/code&gt; comes in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;listener&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;tork&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Job&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="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;tork&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JobStateCompleted&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Execution&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&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;Result&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Execution&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&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;Error&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// pass the listener to the submit job call&lt;/span&gt;
&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SubmitJob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;listener&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;err&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;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"output"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since the job listener is not executing in the "main" thread/goroutine we need a way to pass it back to the main thread. Luckily, Golang has this really convenient thing called a &lt;a href="https://go.dev/tour/concurrency/2" rel="noopener noreferrer"&gt;channel&lt;/a&gt; which does exactly that.&lt;/p&gt;

&lt;p&gt;OK, let's see if this works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"content-type:application/json"&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"language":"bash","code":"echo hello world"}'&lt;/span&gt; http://localhost:8000/execute
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"output"&lt;/span&gt;:&lt;span class="s2"&gt;"hello world&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nice!&lt;/p&gt;

&lt;h2&gt;
  
  
  Security
&lt;/h2&gt;

&lt;p&gt;Let's update our &lt;code&gt;Task&lt;/code&gt; definition to enforce a more strict set of security constraints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;"execute code"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;Limits&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Limits&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;CPUs&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="s"&gt;".5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c"&gt;// no more than half a CPU&lt;/span&gt;
    &lt;span class="n"&gt;Memory&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"20m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c"&gt;// no more than 20MB of RAM&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;Timeout&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;"5s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c"&gt;// terminate container after 5 seconds&lt;/span&gt;
  &lt;span class="n"&gt;Networks&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"none"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c"&gt;// disable networking&lt;/span&gt;
  &lt;span class="n"&gt;Files&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;er&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Code&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;Let's disable Tork's built-in endpoints:&lt;/p&gt;

&lt;p&gt;Create a file named &lt;code&gt;config.toml&lt;/code&gt; in the root of your project with the following contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# config.toml&lt;/span&gt;
&lt;span class="nn"&gt;[coordinator.api]&lt;/span&gt;
&lt;span class="py"&gt;endpoints.health&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;endpoints.jobs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="py"&gt;endpoints.tasks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="py"&gt;endpoints.nodes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="py"&gt;endpoints.queues&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="py"&gt;endpoints.stats&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when you start the project you should see that Tork picked up the config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% go run main.go run standalone          
7:08PM INF Config loaded from config.tom
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Frontend
&lt;/h2&gt;

&lt;p&gt;Let's try to get the frontend to talk to our backend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone git@github.com:runabol/code-execution-demo.git
&lt;span class="nb"&gt;cd &lt;/span&gt;code-execution-demo/frontend
npm i
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And open &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Scaling Up
&lt;/h2&gt;

&lt;p&gt;The last point we are left to address is scalability. &lt;/p&gt;

&lt;p&gt;There are many ways to tweak Tork for scalability, but for our purposes here we'll keep it simple and do the bare minimum of starting a RabbitMQ broker which will allow us to distribute the task processing: &lt;/p&gt;

&lt;p&gt;Start a RabbitMQ broker. Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;tork-rabbit &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 5672:5672 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 15672:15672 &lt;span class="se"&gt;\&lt;/span&gt;
  rabbitmq:3-management
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, add the following to your &lt;code&gt;config.toml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[broker]&lt;/span&gt;
&lt;span class="py"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"rabbitmq"&lt;/span&gt;

&lt;span class="nn"&gt;[broker.rabbitmq]&lt;/span&gt;
&lt;span class="py"&gt;url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"amqp://guest:guest@localhost:5672"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stop Tork if it's currently running.&lt;/p&gt;

&lt;p&gt;Start the Tork Coordinator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go run main.go run coordinator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From a separate terminal window start a worker. You can also start additional workers if you like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go run main.go run worker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using &lt;code&gt;curl&lt;/code&gt; or the frontend try to submit a code snippet. &lt;/p&gt;

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

&lt;p&gt;Hope you enjoyed this tutorial as much as I did. &lt;/p&gt;

&lt;p&gt;The full source code can be found on &lt;a href="https://github.com/runabol/code-execution-demo" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>go</category>
      <category>distributed</category>
      <category>code</category>
    </item>
    <item>
      <title>Building a distributed workflow engine from scratch</title>
      <dc:creator>Arik</dc:creator>
      <pubDate>Fri, 25 Aug 2023 22:00:00 +0000</pubDate>
      <link>https://forem.com/acoh3n/building-a-distributed-workflow-engine-from-scratch-22kl</link>
      <guid>https://forem.com/acoh3n/building-a-distributed-workflow-engine-from-scratch-22kl</guid>
      <description>&lt;p&gt;I've been somewhat obsessed with creating workflow engines for the better part of a decade. The idea of constructing a 'mega' machine from an army of smaller machines never seems to get old for me.&lt;/p&gt;

&lt;p&gt;At their core, workflow engines are responsible for executing a series of tasks (typically referred to as a 'job',  'pipeline' or 'workflow') over a cluster of machines (typically referred to as 'workers' or nodes) as quickly and as efficiently as possible.&lt;/p&gt;

&lt;p&gt;Building a workflow engine comes with a bunch of interesting challenges. Here's a short and highly non-exhaustive list:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;What do you use to author workflows? Do you use a general-purpose programming language? a configuration-type language like JSON or YAML or do you roll your own DSL (Domain Specific Language)?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How do we decide which tasks go to which workers such that busy workers are not overloaded while others are idle?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How do we deal with the requirement to scale up or down the capacity in response to fluctuations in computational demand?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How do we deal with intermittent task failures?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How do we deal with worker crashes?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How do we deal with a situation where we have more tasks to execute than available capacity?&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Let's put some rubber on the road
&lt;/h2&gt;

&lt;p&gt;The first time I needed to actually build a workflow engine was while working for a video streaming startup. At the time, the company was outsourcing all its video processing needs to another company. &lt;/p&gt;

&lt;p&gt;The existing process was slow, expensive and brittle. The company was regularly getting new content (movies, trailers, bonus video material, closed captions etc.) and we needed a way to quickly process this content in order to get it up on the service for customers to enjoy.&lt;/p&gt;

&lt;p&gt;Moreover, the existing process was quite rigid and any changes to it (e.g. to introduce a new audio technology) took months or were simply not possible. I suggested to build a proof-of-concept that would allows us to bring the work in-house and luckily my managers were open to the idea.&lt;/p&gt;

&lt;p&gt;At this point, you're probably asking yourself why would you want to be build one when there are a million open-source and commercial options out there?&lt;/p&gt;

&lt;p&gt;True, there are &lt;a href="https://github.com/meirwah/awesome-workflow-engines" rel="noopener noreferrer"&gt;many options&lt;/a&gt; out there. And we looked at a good number before we made the decision to build one ourselves. But at least at the time (circa 2014), many of the existing options were either not designed for a distributed environment, were designed more particularly for data-processing use cases, were seemingly abandoned, or simply felt over-engineered to our taste.&lt;/p&gt;

&lt;p&gt;The initial iteration of the workflow engine allowed us to start processing 'low-risk' content such as trailers, and as we gained confidence in the new system we slowly phased out the old process completely. &lt;/p&gt;

&lt;p&gt;Later on, when a co-worker left to another media company that needed a similar system, he asked me if I'd like to come over and do it all over again from scratch. Naturally, I agreed. Our 2.0 was similar in spirit but a lot of the lessons learned from the old design were fixed in the new design. &lt;/p&gt;

&lt;h2&gt;
  
  
  Meet Tork
&lt;/h2&gt;

&lt;p&gt;After building two proprietary workflow engines for highly specialized use cases I had an itch to see if other companies - possibly with vastly different use cases - could also benefit from a similar system. So I decided to build an open-source version of it.&lt;/p&gt;

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

&lt;p&gt;Tork is a Golang-based implementation which is very similar in spirit to its closed-source predecessors. It can run in a 'standalone' mode on a laptop or deployed to a huge cluster of machines depending on your need.&lt;/p&gt;

&lt;p&gt;The main components of Tork are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Coordinator&lt;/strong&gt;: responsible for managing the lifecycle of jobs and tasks, routing tasks to the right workers and for dealing with task execution errors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Worker&lt;/strong&gt;: responsible for executing tasks according to the instructions of the Coordinator. Workers are stateless so it's easy to add and remove them as demand for capacity changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Broker&lt;/strong&gt;: the means of communication between the Coordinator and worker nodes. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Datastore&lt;/strong&gt;: holds the state for tasks and jobs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Runtime&lt;/strong&gt;: tasks are executed by means of a runtime which translates the task into actual executable. Currently only Docker is supported due to its ubiquity and large library of images, but there are plans to add support for Podman and WASM in the future.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Hello world
&lt;/h3&gt;

&lt;p&gt;Tork jobs are authored in YAML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# hello.yaml&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hello job&lt;/span&gt;
&lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;say hello&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu:mantic&lt;/span&gt; &lt;span class="c1"&gt;# docker image&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt; &lt;span class="c1"&gt;# arbitrary script&lt;/span&gt;
      &lt;span class="s"&gt;echo -n hello world &lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;say goodbye&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu:mantic&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;echo -n bye world&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and submitted through the API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JOB_ID=$(curl \
  -s \
  -X POST \
  --data-binary @hello.yaml \
  -H "Content-type: text/yaml" \
  http://localhost:8000/jobs | jq -r .id)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To query for a job's status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -s http://localhost:8000/jobs/$JOB_ID | jq .

{
  "id": "ed0dba93d262492b8cf26e6c1c4f1c98",
  "state": "COMPLETED",
  ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tasks can also specify auto-retry count, timeout, enforce CPU and RAM limits and do other fun things such as conditionals, loops and parallel execution.&lt;/p&gt;

&lt;p&gt;If you're interested in checking it out, you can find the project on Github: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Backend: &lt;a href="https://github.com/runabol/tork" rel="noopener noreferrer"&gt;https://github.com/runabol/tork&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Web UI: &lt;a href="https://github.com/runabol/tork-web" rel="noopener noreferrer"&gt;https://github.com/runabol/tork-web&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>workflowengine</category>
      <category>go</category>
      <category>opensource</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Making your relational database a little more graphy</title>
      <dc:creator>Arik</dc:creator>
      <pubDate>Fri, 21 Jun 2019 01:25:34 +0000</pubDate>
      <link>https://forem.com/acoh3n/making-your-relational-database-a-little-more-graphy-49b</link>
      <guid>https://forem.com/acoh3n/making-your-relational-database-a-little-more-graphy-49b</guid>
      <description>&lt;p&gt;When it comes to storing data, relational database had always been my go-to solution. They're reliable, they're mature, their Structured Query Language (or SQL) is quite powerful and if you design and treat them well, they generally provide great performance.&lt;/p&gt;

&lt;p&gt;In relational databases, everything is a table. So for example if you want to store -- say a list of customers -- then you will probably create a &lt;code&gt;customers&lt;/code&gt; table where these will be stored.&lt;/p&gt;

&lt;p&gt;For each table in your database you would also define the pieces of information you want to store on each item in the table. These pieces of information are technically known as "fields".&lt;/p&gt;

&lt;p&gt;Here's an example of a very simple &lt;code&gt;customers&lt;/code&gt; table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE customers (
  id int,
  last_name varchar(255),
  first_name varchar(255),
  email_address varchar(255)
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you also want to store -- say, the customer orders -- you can create an &lt;code&gt;orders&lt;/code&gt; table where each item (or row) in the table would be an order  with a link (or relation) to the customer who made the order.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE orders (
  id int,
  customer_id int,
  order_date date,
  order_status varchar(10),
  order_total decimal
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That second field -- &lt;code&gt;customer_id&lt;/code&gt; -- is the id of the customer in the &lt;code&gt;customers&lt;/code&gt; table and is what creates the relation between items in the &lt;code&gt;orders&lt;/code&gt; table to items in the &lt;code&gt;customers&lt;/code&gt; table. &lt;/p&gt;

&lt;p&gt;This is a great way to model your data. And in fact many many software projects are built in just this way.&lt;/p&gt;

&lt;p&gt;More recently a new type of database started to become more mainstream: Graph Database. Graph databases take a slightly different approach to thinking/modeling your data.&lt;/p&gt;

&lt;p&gt;Rather than thinking of your data as a series of tables, it encourages you to think about your data as a network of objects. So a typical example would be your Facebook/Linkedin network. You are connected to someone, that person is connected in turn to someone else and so on.&lt;/p&gt;

&lt;p&gt;In graph databases there are really only two types of things: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Vertex/Node - the fundamental unit which make up the elements of your graph. So a "Friend" in the Facebook example would be a node/vertex.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Edge - acts as a link between nodes/vertices.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's an example of what this might look like:&lt;/p&gt;

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

&lt;p&gt;So the yellow circles are nodes/vertices and the lines are the edges. &lt;/p&gt;

&lt;p&gt;On the surface this might seem pretty similar to the relational database idea of relations. That's true so long as your network of objects isn't too "wide". Once you have many "degrees of relations" -- i.e. an object links to an object which links to another one and so on -- SQL queries can become somewhat unwieldy to deal with.&lt;/p&gt;

&lt;p&gt;This was all interesting to me when I first learned about it, but because I didn't have any practical application for it at the time, I parked it at the back of my head. &lt;/p&gt;

&lt;p&gt;And then one day I was faced with an interesting problem I hadn't had to deal with in the past: building a Content Management System. Let's leave aside for a second the build vs. not build a CMS discussion. This is not the point of this article. Let's just say that we had no choice but to build one.&lt;/p&gt;

&lt;p&gt;This thing with CMSes though, is that unlike traditional customers/orders type databases, they typically have a much richer set of objects. So in our case, being in the television industry, we had to store films and episodes and series and videos and things like that. But we also wanted to drive the entire experience on the screen straight from our CMS. &lt;/p&gt;

&lt;p&gt;That means that we wanted to give our editors the power to define how the homepage would look like for various types of users at a certain point in time. Or we wanted them to schedule certain collection of movies that would appear on the homepage (think Netflix type of experience). Or we wanted certain collection of movies to be driven automatically based on the user interaction with the website. &lt;/p&gt;

&lt;p&gt;Looking over this data model it was clear that we had a fairly complex network of objects in our hands. It was at this point that I recalled that graph database thing I parked at the back of my head. This seems like a perfect fit for it.&lt;/p&gt;

&lt;p&gt;I was sold on the idea of using a "graphy" approach but I wasn't sold about the idea of using anything but my venerable relational databases. None of the "real" graph databases seemed to have the level of maturity and robustness I learned to love in the many years of using a relational database. &lt;/p&gt;

&lt;p&gt;So I wondered if there was a way for me to eat my cake and have it too. Or use a relational database but as a graph database. There were a couple of things I had to solve in order to make this happen:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How do I store the data?&lt;/li&gt;
&lt;li&gt;How do I query the data without writing complicated and therefore brittle SQL queries.&lt;/li&gt;
&lt;li&gt;What about performance?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first problem ended up being relatively easy to solve:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;create table node (
  id          varchar(64) primary key,
  node_type   varchar(64) not null,
  created_at  timestamp not null default current_timestamp,
  modified_at timestamp,
  properties  jsonb not null,
  deleted     boolean not null default false
);

create table edge (
  id           varchar(64) primary key,
  edge_type    varchar(64) not null,
  created_at   timestamp not null default current_timestamp,
  modified_at  timestamp,
  from_node_id varchar(64) not null references node (id),
  to_node_id   varchar(64) not null references node (id),
  properties   jsonb not null,
  deleted      boolean not null default false
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using just two tables I was able to get any conceivable object stored in the &lt;code&gt;node&lt;/code&gt; table and be able to arbitrarily connect it to any other object using the &lt;code&gt;edge&lt;/code&gt; table. Also, using PostgreSQL's &lt;code&gt;jsonb&lt;/code&gt; table I did away with the need to alter my schema ever again to add custom properties/fields.&lt;/p&gt;

&lt;p&gt;To solve the second problem, I wrote a pretty thin wrapper around my SQL library to allow me to query my graph of objects in a "graphy" way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; // list all actors for the home alone movie
 Traversal&amp;lt;Node&amp;gt; t = g.nodes().type("Movie").eq("title","Home Alone").to("Actor");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the third problem, I had to use a little bit of caching magic on the application side. But since the data model is really simple (2 tables) it ended up being pretty straightforward to accomplish. &lt;/p&gt;

&lt;p&gt;The solution I just described here ended up being used to power every aspect of our website and mobile apps: &lt;a href="https://watch.smithsonianchannel.com" rel="noopener noreferrer"&gt;https://watch.smithsonianchannel.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>graph</category>
      <category>sql</category>
      <category>relational</category>
    </item>
    <item>
      <title>The power of abstraction</title>
      <dc:creator>Arik</dc:creator>
      <pubDate>Thu, 06 Dec 2018 02:13:18 +0000</pubDate>
      <link>https://forem.com/acoh3n/the-power-of-abstraction-1gpa</link>
      <guid>https://forem.com/acoh3n/the-power-of-abstraction-1gpa</guid>
      <description>

&lt;p&gt;If someone had asked me "what is the number 1, absolutely most important concept in all of software development?" I would answer it using one word: "abstraction". &lt;/p&gt;

&lt;p&gt;Abstraction is all about reducing an idea to its absolute essence. &lt;/p&gt;

&lt;p&gt;Let's look at an example: take the activity of running. If you take a closer look at what is actually happening in your body while you run, your head would spin: a myriad of muscles are keeping your body balanced, your heart is pumping blood like crazy, your lungs are working full speed to keep your blood oxygenated, your sweat glands are pouring sweat on your skin to keep you cool and on and on. &lt;/p&gt;

&lt;p&gt;But to you it's simply &lt;em&gt;running&lt;/em&gt;. Your mind simply abstracted, or removed the non-essential details from this concept of running so you can easily think about it. &lt;/p&gt;

&lt;p&gt;Let's look at another example. Here's some code: &lt;/p&gt;

&lt;pre&gt;var splitString = str.split("");
var reverseArray = splitString.reverse();
var joinArray = reverseArray.join("");
return joinArray;&lt;/pre&gt;

&lt;p&gt;Now let's add abstraction: &lt;/p&gt;

&lt;pre&gt;
function reverseString (str) {
  var splitString = str.split("");
  var reverseArray = splitString.reverse();
  var joinArray = reverseArray.join("");
  return joinArray;
}&lt;/pre&gt;

&lt;p&gt;In the first example we have to read every line of code in sequence and keep track of what's happening in order to understand it. If this was part of a larger piece of code we would potentially have to do that over and over again throughout the lifetime of the software. &lt;/p&gt;

&lt;p&gt;In the second example however, we give a name to that piece of code which lets us ignore the internal details and keep the essential concept in mind: reversing a string. Aha! &lt;/p&gt;

&lt;p&gt;This idea is so central to computers (and life, really) that when you think about it for a moment you realize that the hardware and software you use every day are composed of "layers" (or abstractions) of software. From silicon to machine code, to assembly code, to the operating system, to your application code, each layer can be easily reasoned about without exploding our heads with details. &lt;/p&gt;

&lt;p&gt;Creating clear abstraction in software is the essence of software design. It's the difference between understandable, easy to maintain software and a nightmare to deal with. &lt;/p&gt;


</description>
      <category>softwaredesign</category>
    </item>
    <item>
      <title>Tell-tales of the expert programmer</title>
      <dc:creator>Arik</dc:creator>
      <pubDate>Sat, 27 Oct 2018 19:52:54 +0000</pubDate>
      <link>https://forem.com/acoh3n/tell-tales-of-the-expert-programmer-1k5m</link>
      <guid>https://forem.com/acoh3n/tell-tales-of-the-expert-programmer-1k5m</guid>
      <description>&lt;p&gt;Early on in my programming career, I was very lucky to have had the opportunity to work with an expert programmer who took me under his wing. (I prefer using the word "expert" over the word "senior", because the word "senior" is too muddied up with vague notions about what it means for someone to be a "senior" programmer). &lt;/p&gt;

&lt;p&gt;Being a young programmer and with very little experience under my belt, I didn't consider my mentor to be particularly exceptional. Sure, he was doing a great job. But having nothing to compare it against, I just figured this is how all programmers perform. Little did I know.&lt;/p&gt;

&lt;p&gt;Over the next 12 years I've crossed paths with many programmers -- some great, some not so much. Nonetheless, having worked with programmers of varying degrees of ability allowed me to put that initial experience into perspective. Moreover, I began noticing certain key characteristics, common to almost all expert programmers I had run into:&lt;/p&gt;

&lt;h3&gt;Craftsmanship&lt;/h3&gt; 

&lt;p&gt;Expert programmers treat their work like the age-old fine craftsmen: quality is king. While average engineers churn out reams and reams of code, expert programmers write code that reads more like poetry than code. Their code has an actual aesthetic quality to it and they believe that "Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away."&lt;small&gt;-Antoine de Saint-Exupery&lt;/small&gt;&lt;/p&gt;

&lt;h3&gt;Responsibility&lt;/h3&gt; 

&lt;p&gt;Expert programmers really &lt;b&gt;own&lt;/b&gt; their work. Expert programmers don't wait around for "sprint planning", to be assigned tasks or for someone else to write "stories" for them. They simply take ownership of the problem and get to work. This also extends to not blindly following rote requirements and just do what their told -- thus passing their responsibility elsewhere . Instead, they constantly challenge the status quo in order to get to the bottom of the situation and to deliver the &lt;b&gt;right&lt;/b&gt; solution. They believe in giving their customers what they need, not what they think they want.&lt;/p&gt;

&lt;p&gt;Expert programmers make mistakes like any other programmers. But rather than blaming the stars, the weather and the dog next door for their faulty code, they get down to business to solve the bug. They do not dismiss bugs as a "one-off glitch" or (god forbid) write workarounds around them. Rather, they find the root cause of the problem and eliminate it.&lt;/p&gt;

&lt;h3&gt;Agility&lt;/h3&gt;

&lt;p&gt;Interestingly, and almost counter-intuitively, expert programmers move very quickly from problem to solution. Despite spending more time on properly designing, writing and testing their solution they usually deliver much quicker than the average programmer. This is because expert programmers rarely start from scratch. Their software is typically built in a way that promotes reusability and extensibility. &lt;/p&gt;

&lt;p&gt;Another advantage of the Expert programmer is that they recognize that the vast majority of problems were already solved time and again by other programmers. These solutions can often be found in the form of code libraries, write-ups and best practices. While average programmers will try to solve the problem with the tools and knowledge they have, expert programmers will seek other viewpoints, even if it means getting into uncharted waters.  &lt;/p&gt;

&lt;h3&gt;Passion&lt;/h3&gt; 

&lt;p&gt;Expert programmers are some of the most passionate individuals I have ever met. They love what they do and their job seems to me more like play than work. As a result, programming is not something they put aside when their work day is over. They usually spend significant amounts of their free time reading about, practicing and improving their craft. It is this diligence of practice that often has the expert programmer appear as exceptionally gifted. What usually passes as talent is actually consistent study and practice over a long period of time. &lt;/p&gt;

&lt;h3&gt;Parting Thoughts&lt;/h3&gt;

&lt;p&gt;If you run into one of these expert programmers, I have but only one piece of advice to give you: "leach" on to them like your life depends on it and learn everything you can learn. No book can replace the one-on-one experience and the gains attendant to apprenticing under an expert programmer. &lt;/p&gt;

&lt;p&gt;Also, if you have a related story to share I'd love to hear about it.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>craft</category>
    </item>
    <item>
      <title>Why I love Java</title>
      <dc:creator>Arik</dc:creator>
      <pubDate>Tue, 23 Oct 2018 02:21:04 +0000</pubDate>
      <link>https://forem.com/acoh3n/why-i-love-java-5c14</link>
      <guid>https://forem.com/acoh3n/why-i-love-java-5c14</guid>
      <description>&lt;p&gt;Java is unarguably one of the most popular programming languages in the world today. Companies like Google, Amazon and Netflix -- to name a few big names -- are using Java to build large portions of their infrastructure and backend services. But despite its huge popularity (or perhaps because of it) Java's reputation among programmers is something of a mixed bag. Some seem to genuinely like it while others hate it.&lt;/p&gt;

&lt;p&gt;Personally, as someone who has been using the language for more than a decade professionally, I find it to be an excellent language. No, it isn't perfect. And the programming world -- being young as it is -- is still learning from its own mistakes. But all other things being equal I think that Java got a lot more right than wrong.&lt;/p&gt;

&lt;p&gt;Following are some of the things I think Java got right:&lt;/p&gt;

&lt;h3&gt;It's a productive language&lt;/h3&gt;

&lt;p&gt;As a programmer I get paid to solve problems. In minimum time and maximum quality. My software is expected to be robust (bug free), performant and maintainable (easily extended). I typically write large, distributed and fairly complex server-side software.&lt;/p&gt;

&lt;p&gt;Java is a purely Object Oriented language. To the uninitiated, this means that you design your code around unit of codes called "objects" which loosely resemble real-world object (or concepts). So if you were to write, say, a library management software you'll most likely have these code objects representing books, members, staff but also more abstract concepts such as genre and loan.&lt;/p&gt;

&lt;p&gt;This happens to be a very neat way to organize software (and your thoughts). Instead of thinking about your system as a big line-by-line, step-by-step algorithm, you think of it as a set of interacting objects. If done right, each one of these objects can be reasoned about independently from other objects. Each object can be tested in isolation from others and each one can be extended without necessarily affecting the entire system. &lt;/p&gt;

&lt;p&gt;Java did not invent the idea of Object Oriented Programming. In fact OOP dates back to the late 60's, but the Java language designers did a great job implementing the idea in the language in such a way that it is practical and productive for the programmer.&lt;/p&gt;

&lt;h3&gt;The Java Virtual Machine&lt;/h3&gt;

&lt;p&gt;One of Java's most convenient features is the Java Virtual Machine (or JVM). The JVM essentially acts as the translator between your Java code and the particular operating system that your code is running on. This is the origin of the once-famous Java marketing slogan "write once, run anywhere". Without the JVM, you'd have to compile your code for every operating system separately. the JVM guarantees that your Java code runs identically on Linux, Mac or Windows. &lt;/p&gt;

&lt;p&gt;The Java language designers also envisioned a world where other languages can execute on the JVM besides Java. To that end they've specified a low-level language (called "bytecode") which is the language that Java complies into and the stuff that actually gets executed on the JVM.  Today there are dozens of languages targeting the JVM as a result.&lt;/p&gt;

&lt;h3&gt;Automatic Memory Management&lt;/h3&gt;

&lt;p&gt;If you ever used a language such as C or C++ then you are intimately familiar with the painstaking effort involved in manually managing memory allocation (and deallocations) in your programs. This is an area, so rife with bugs that the designers of the Java Programming Language decided to do away with it completely. Rather than giving the programmer the opportunity to shoot themselves in the foot they decided to let Java do all the memory management for them -- automatically. &lt;/p&gt;

&lt;p&gt;In Java, the programmer simply creates whatever objects they need (without explicitly worrying about allocating memory for it) and Java will automatically reclaim that memory once the object is no longer used by the program.&lt;/p&gt;

&lt;h3&gt;Standing on the shoulders of giants&lt;/h3&gt;

&lt;p&gt;Java was designed and implemented by some of the brightest people in the Computer Science world. People such a Doug Steele, Joshua Bloch, Mark Reinhold and Brian Goetz are true masters of their craft and are a constant source of inspiration and learning for me. Not just about Java per se, but more importantly, about writing better software in general.&lt;/p&gt;

&lt;h3&gt;Huge community&lt;/h3&gt;

&lt;p&gt;As of this writing, according to Wikipedia, there are 9 million Java developers around the world. This is a huge advantage because for just about every problem you run into as a developer there is a high likelihood that someone, somewhere had already solved a variation of this problem or that very same problem. Usually a simple online search will reveal multiple sources that can be used to solve or at the very least approach the problem. &lt;/p&gt;

&lt;h3&gt;Fantastic frameworks &amp;amp; libraries&lt;/h3&gt;

&lt;p&gt;Java has an enormous array of frameworks and libraries to choose from. From logging, to web development, to database connectivity, to messaging clients, there's a library (or several) to help solve just about any problem. A particular favorite of mine is the Spring Framework which had become the defacto framework for any sort of work involving web (HTTP) technologies. &lt;/p&gt;

&lt;p&gt;Writing web application using "raw" Java would be a tedious task, to say the least. Moreover, the designers of Spring noticed that many programmers are trying to solve the same (or very similar) problems and each one is solving these problems slightly differently. Spring (and its vast portfolio of sub-projects) are meant to give the programmer a leg-up by giving them a solid set of building blocks to build upon for their projects.&lt;/p&gt;

&lt;h3&gt;Closing thoughts&lt;/h3&gt; 

&lt;p&gt;There are many fine languages to choose from out there. Java is just one of them. This article is in no way trying to claim that "Java is the best" or that "Java is better than X language". It is simply meant as an acknowledgement to the fine work that made Java possible.&lt;/p&gt;

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