<!DOCTYPE html>

<!-- Welcome traveler. 

You may have wandered to my website's source code out of curiosity,
or to learn something new. I've left a few comments here and there
for those who want to learn about HTML and building websites.

-->

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>
      Syntax Error #7 : Juha-Matti Santala
    </title>

    <!-- RSS Feed

    This link tells RSS readers where to find my feed so you don't have
    to manually enter the entire path to the XML file but can jump right
    into pasting the main page URL and the readers should find the right
    feed for you.

    RSS feeds are a great way to give readers the power to subscribe to
    a blog with the tooling they want to.
    -->
    <link
      rel="alternate"
      type="application/rss+xml"
      title="hamatti.org &raquo; Feed"
      href="https://hamatti.org/feed/feed.xml"
    />

    <!-- Metadata 

  Metadata is used in a few places, most notably when
  sharing links in social media or messaging platforms.

  -->

<!-- That's my name! -->
<meta name="author" content="Juha-Matti Santala" />

<!-- Description tells what this page is about -->
<meta
  name="description"
  content="The home of a developer community specialist."
/>

<!-- Open Graph

  og stands for Open Graph and it's a specification for 
  defining social media preview content. It was created by 
  Facebook but many other platforms use it too.

  -->

<meta property="og:site_name" content="Juha-Matti Santala - Community Builder. Dreamer. Adventurer." />
<meta property="og:locale" content="en_US" />
<meta
  property="og:title"
  content="Syntax Error #7"
/>
<meta
  property="og:description"
  content="The home of a developer community specialist."
/>

<!-- 

    This URL is important: it's where the preview will lead
    when clicked.

    If it's incorrect, the reader experience will be degraded.

  -->
<meta property="og:url" content="https://hamatti.org/syntax-error/syntax-error-7" />

<!--
    
    These couple of image definitions help services choose
    which images they should show in the preview.

    Note that these don't need to even appear on the page.

    If these are not defined, many platforms show the first
    image they find on a page.

  -->

<meta
  property="og:image"
  content="https://hamatti.org/"
/>
<meta
  property="og:image:secure_url"
  content="https://hamatti.org/"
/><!-- Fediverse:creator

  Similar to Open Graph definitions above, this one
  was created by the developers of Mastodon to let 
  the system know which Mastodon account is behind
  this page and can link to it.

  -->
<meta name="fediverse:creator" content="@hamatti@mastodon.world" />

<!-- Twitter / X

  X (previously Twitter) has their own set of
  meta tags they use to define what to show in
  a preview.

  -->
<meta
  name="twitter:card"
  content="summary"
/>
<meta
  name="twitter:site"
  content="@"
/>
<meta
  name="twitter:creator"
  content="@"
/>

<!-- Canonical URL

  If a post is originally published elsewhere and 
  then shared on my site, I point the canonical URL
  to that page to let computers - mainly search engine
  scrapers - to know where the original exists.

  -->
<link rel="canonical" href="https://hamatti.org/syntax-error/syntax-error-7" />

<!-- Generator

  This site is a statically generated site so I share which
  tool I used to generate it.

  Since my site is static, it's safe to include this but for 
  something using a dynamic backend (like WordPress or Django),
  it can cause security issues as it lets potentially malicious
  user to know what systems and versions you may be running.

  -->
<meta name="generator" content="Eleventy v2.0.1" />

<!-- Mastodon verification

  These links verify that when I link my website to my
  Mastodon accounts, those accounts are really me.
  
-->
<link rel="me" href="https://mastodontti.fi/@hamatti" />
<link rel="me" href="https://mastodon.world/@hamatti" />


<script type="application/ld+json">
  {
    "name": "Juha-Matti Santala",
    "description": "The home of a developer community specialist.",
    "author": {
      "@type": "Person",
      "name": "Juha-Matti Santala"
    },
    "@type": "WebSite",
    "url": "https://hamatti.org",
    "image": "",
    "headline": "Juha-Matti Santala - Community Builder. Dreamer. Adventurer.",
    "sameAs": [
      "",
      ""
    ],
    "@context": "http://schema.org"
  }
</script>


    <!-- CSS 

    It's not usually the best practice to provide many CSS files but
    to rather combine them in the build phase into one to avoid HTTP
    requests on read time.

    I have been lazy to set that up with Eleventy so here are all my
    CSS declarations in a human-readable format.
    -->
    <link href="/assets/fonts/roboto-slab.css" rel="stylesheet" />
    <link rel="stylesheet" href="/assets/reset.css" />
    <link rel="stylesheet" href="/assets/layout.css" />
    <link rel="stylesheet" href="/assets/typography.css" />
    <link rel="stylesheet" href="/assets/colors.css" />
    <link rel="stylesheet" href="/assets/page.css" />
    <link rel="stylesheet" href="/assets/blog.css" />
    <link rel="stylesheet" href="/assets/header.css" />
    <link rel="stylesheet" href="/assets/navigation.css" />
    <link rel="stylesheet" href="/assets/links.css" />
    <link rel="stylesheet" href="/assets/newsletter.css" />
    <link rel="stylesheet" href="/assets/footer.css" />
    <link rel="stylesheet" href="/assets/main.css" />
    <link rel="stylesheet" href="/assets/landing.css" />
    <link rel="stylesheet" href="/assets/uses.css" />
    <link rel="stylesheet" href="/assets/prism.css" />
    <link rel="stylesheet" href="/assets/prism-ext-ptcgo.css" />
    <link rel="stylesheet" href="/assets/print.css" media="print" />
    <link
      rel="stylesheet"
      href="/assets/prism-vs-code-plus.css"
    />
    <link rel="stylesheet" href="/assets/adventofcode.css" />
    <link rel="stylesheet" href="/assets/embeds.css" />

    <link rel="icon" href="/assets/img/favicon.png" />
    <link rel="apple-touch-icon" href="/assets/img/favicon.png" />

    <!-- Webmentions

    Webmentions are a way for websites to talk to each other.
    If you write a blog post that links to any of my pages on
    this site, you can send me a Webmention to the URL below
    and I will get a notification to know that we're now in
    blogosphere discussion.
    -->
    <link
      rel="webmention"
      href="https://webmention.io/hamatti.org/webmention"
    />
  </head>

  <body class="line-numbers">
    <div id="layout-top">
      <header><div>
  <a href='/'>Juha-Matti Santala</a>
  <div>Community Builder. Dreamer. Adventurer.</div>
</div>
</header>
      <nav aria-label="Main"><ul>
  <li><a href="/" >Home</a></li>
  <li><a href="/blog" >Blog</a></li>
  <li><a href="https://notes.hamatti.org">Notes</a></li>
  <li><a href="/weeklies" >Weeklies</a></li>
  <li><a href="/snacks" >Snacks</a></li>
  <li><a href="/codebase" >codebase</a></li>
  <li><a href="/speaking" >Speaking</a></li>
  <li><a href="/software" >Software</a></li>
  <li><a href="/about" >About me</a></li>
  <li><a href="/feed/feed.xml" class="icon"><svg role="img" labelled-by="RSS-SVG-ID" version="1.1" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 32 32">
<title id="RSS-SVG-ID">RSS</title>
<path fill="currentColor" d="M4.259 23.467c-2.35 0-4.259 1.917-4.259 4.252 0 2.349 1.909 4.244 4.259 4.244 2.358 0 4.265-1.895 4.265-4.244-0-2.336-1.907-4.252-4.265-4.252zM0.005 10.873v6.133c3.993 0 7.749 1.562 10.577 4.391 2.825 2.822 4.384 6.595 4.384 10.603h6.16c-0-11.651-9.478-21.127-21.121-21.127zM0.012 0v6.136c14.243 0 25.836 11.604 25.836 25.864h6.152c0-17.64-14.352-32-31.988-32z"></path>
</svg>
</a></li>
  <li><a href="/search" class="icon"><?xml version="1.0"?>
<svg class="feather feather-search" fill="none" height="24" stroke="currentColor"
    stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" width="24"
    xmlns="http://www.w3.org/2000/svg"
    aria-label="search">
    <circle cx="11" cy="11" r="8" />
    <line x1="21" x2="16.65" y1="21" y2="16.65" />
</svg></a></li>
  <li><button aria-label="Toggle light/dark mode" id="toggleTheme"><svg width="32px" height="32px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink">
    <title>Toggle dark/light mode</title>
    <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
        <g fill="currentColor" fill-rule="nonzero">
            <path
                d="M12,22 C17.5228475,22 22,17.5228475 22,12 C22,6.4771525 17.5228475,2 12,2 C6.4771525,2 2,6.4771525 2,12 C2,17.5228475 6.4771525,22 12,22 Z M12,20.5 L12,3.5 C16.6944204,3.5 20.5,7.30557963 20.5,12 C20.5,16.6944204 16.6944204,20.5 12,20.5 Z">
            </path>
        </g>
    </g>
</svg></button></li>
</ul></nav>
    </div>

    <main>
<div id="syntax-error-header">
  <img src="/assets/img/syntax-error/banner.png" alt="" />
  
  <a href="/syntax-error/">Back to index</a>
  
</div>
<div id="page"><h1>Syntax Error #7</h1>
<p>Hello!</p>
<p><img src="/assets/img/syntax-error/pycon-lightning-talk.png" alt="Juhis speaking in front of large crowd in a conference hall in old monastery."></p>
<p>As I'm sending this newsletter, I'm enjoying the lovely Czech Python community at <a href="https://cz.pycon.org/2023/">PyCon CZ</a>. Prague has been beautiful as always and I got the pleasure to entertain the audience with my lightning talk about the wild west of version numbering schemes.</p>
<p>If you're working with Python and want to experience the best, most friendly and loveliest and warmest conference, I wanna recommend joining PyCon CZ next year. I've been here twice and both times have been fantastic.</p>
<hr>
<h2>Javascript bug and its debug</h2>
<p>Let's start this month with a bit of role play: imagine that you are a web developer working in an educational institute and you are part of a team that's responsible for the part of code that grades the student's course work to be displayed in online protal and their certificates.</p>
<p>It's a bit of legacy system but things have been working okay. You get the scores for a student per course from an API developed by a third party vendor.</p>
<p>Then one day, all hell breaks lose. Students start to report through their teachers and administration that the grades are all wrong and some of them are worried it will cost them their future opportunities. The grades are still reported but they are bit inconsistently incorrect: sometimes they get some students right and sometimes they may fail a student who would have otherwise gotten a high grade.</p>
<p>That's a stressful situation to be.</p>
<h3>Let's debug!</h3>
<p>In a situation like this, my first approach is to start from the end user's perspective: in this case the web portal. If I'm not sure what part of the system is responsible for what calculations, I'd start by logging in and seeing what API calls are being made and what they return.</p>
<p>In Firefox, I'd do this by opening the Dev Tools and heading over to the Network tab. I find the right call from the list (I discover that frontend calls endpoint <code>/grades</code>) and from the Response tab on the right pane, I can see that the backend is sending us the final grades.</p>
<p><img src="/assets/img/syntax-error/network-json.png" alt="Network tab with a request returning a JSON with four students and their grades"></p>
<p>This helps me divide the problem space in half: I know the error is not in the frontend code. That's why I always start with this step as it saves a lot of time.</p>
<h3>Moving to backend</h3>
<p>As I learned through exploration in the last step that my code calls the endpoint <code>/grades</code>, my next step is to open the routing files in the backend code to see what happens when <code>/grades</code> gets a GET request.</p>
<p>Following through a few hoops, I find that we have a <code>getGrades</code> function that is responsible for grading.</p>
<pre class="language-javascript"><code class="language-javascript">function grade(score) {
  if (score > 70) return "A";
  if (score > 50) return "B";
  if (score > 30) return "C";
  if (score > 10) return "D";
  return "F";
}

async function getGrades(student, course) {
  const scoresFromAPI = await getScores(student, course);
  const scores = scoresFromAPI.map(parseInt);
  const total = calculateTotal(scores);
  const grade = grade(total);
  return grade;
}</code></pre>
<p>On a quick glance, everything seems normal: we get the scores as strings (remember how I said we use 3rd party APIs, you sometimes find funky stuff like this in real life) and we convert them to integers with Javascript's <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt">parseInt function</a>, then calculate the total score and finally get the grade and return that.</p>
<p><em>(If you're an experienced Javascript developer or have been burned by this recently, you might already know the issue. Play along, don't spoil it for the crowd.)</em></p>
<p>I'd start by adding a <code>console.log</code>, <a href="/syntax-error/syntax-error-2-print-it-like-a-boss/">my first tool in the toolbox for every debugging</a> into the function. First, to make sure it's being run through here and second, to see what we get.</p>
<pre class="language-javascript"><code class="language-javascript">async function getGrades(student, course) {
  const scoresFromAPI = await getScores(student, course);
  console.log({ scoresFromAPI });
  const scores = scoresFromAPI.map(parseInt);
  const total = calculateTotal(scores);
  const grade = grade(total);
  return grade;
}</code></pre>
<p>When I now refresh the dev environment, I can see that the scores are indeed coming in:</p>
<pre><code class="language-plain">{
  scoresFromAPI: [&quot;14&quot;, &quot;10&quot;, &quot;13&quot;, &quot;10&quot;]
}
</code></pre>
<p>Good, now we've confirmed that we are in the right place (<a href="/syntax-error/syntax-error-4-refreshing-wrong-window/">and we're in the right environment</a>).</p>
<p>Next, maybe I want to make sure they get parsed correctly:</p>
<pre class="language-javascript"><code class="language-javascript">async function getGrades(student, course) {
  const scoresFromAPI = await getScores(student, course);
  const scores = scoresFromAPI.map((score) => {
    let parsed = parseInt(score);
    console.log(parsed);
    return parsed;
  });
  const total = calculateTotal(scores);
  const grade = grade(total);
  return grade;
}</code></pre>
<pre><code class="language-plain">14
10
13
10
</code></pre>
<p>Once again, everything looks to be in order, hmm. I then go refresh my page again and I notice now the grades have changed a bit, that's odd. All I did was add some logging statements with no side effects but the results are different.</p>
<p>You roll back that change and confirm that things are broken again. Sometimes one just gets stuck.</p>
<h3>Becoming a code historian</h3>
<p>History is a good teacher. I often use version control's history to see what recent changes may have happened here that could explain.</p>
<p>With the help of <code>git blame</code> and following the trail of changes within this function, you find a commit where it was changed:</p>
<pre class="language-javascript"><code class="language-javascript">async function getGrades(student, course) {
- const scores = await getScores(student, course);
+ const scoresFromAPI = await getScores(student, course);
+ const scores = scoresFromAPI.map(parseInt);
  const total = calculateTotal(scores);
  const grade = grade(total);
  return grade;
}</code></pre>
<p>The explanation tells you that the API for some mysterious reason changed from returning a list of integers to returning a list of strings so the developer who made the change, added a map function that parses them to integers.</p>
<p>But we checked that and those scores were parsed correctly – at least when we printed them out.</p>
<p>Here's a short Javascript lesson: the functions that you pass as callbacks to other functions like <code>map</code> and <code>filter</code> need to have a specific signature or they can fail horribly. <a href="https://jakearchibald.com/2021/function-callback-risks/">Jake Archibald has a great blog post going in depth with this</a>.</p>
<p>In essence, the callback function provided to <code>map</code>, <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map">is passed three arguments</a>: the element, its index and the array it came from. On the other hand, <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt">parseInt</a> takes in two arguments: the number and its base.</p>
<p>So what happens here is that we actually call <code>parseInt</code> with values <code>(14, 0), (10, 1), (13, 2) and (10, 3)</code> so instead of converting them into integers base 10 (decimal), we try to convert numbers into base 0, 1, 2 and 3 - causing them to fail in a way that still often returns a number.</p>
<p>And what you as the developer in this role play didn't either look into or consider anymore is that the <code>calculateTotal</code> function converted any <code>NaN</code>s to 0 because sometimes missing scores were inregularly marked in the source data.</p>
<h3>Happy end</h3>
<p>We started the debugging journey from the browser, found our way through network requests and routes to our function and finally after a while of bouncing around, found a helpful hint from the git history that allowed us to fix the code.</p>
<p>The fix? To change the map line into <code>const scores = scoresFromAPI.map(score =&gt; parseInt(score))</code> which so easily looks to do the same thing when it actually doesn't.</p>
<hr>
<h2>Story Time</h2>
<p><em>If you have debugging stories or examples you want to share to the Syntax Error community, please reach out via hello@syntaxerror.tech and we might share your story!</em></p>
<p>I ran into this interesting post <a href="https://ruby0x1.github.io/machinery_blog_archive/post/a-taxonomy-of-bugs/index.html">A Taxonomy of Bugs</a> the other day. Niklas Gray wrote an interesting categorization of different types of bugs. He categorized them as:</p>
<ul>
<li>The Logical Error</li>
<li>The Unexpected Initial Condition</li>
<li>The Memory Leak</li>
<li>The Memory Overwrite</li>
<li>The Design Flaw</li>
<li>The Third-Party Bug</li>
<li>The Failed Specification</li>
<li>The Hard-To-Reproduce Bug</li>
<li>The Compiler Bug</li>
</ul>
<p>He talks about each of these cases and I really like that he included things that might not traditionally be considered <em>bugs</em> but definitely have similar outcomes like design flaws and failed specs.</p>
<p>Head over to <a href="https://ruby0x1.github.io/machinery_blog_archive/post/a-taxonomy-of-bugs/index.html">https://ruby0x1.github.io/machinery_blog_archive/post/a-taxonomy-of-bugs/index.html</a> and give it a read!</p>
<hr>
<p><em>Syntax Error is created with love by <a href="/">Juhis</a>. If you liked it, why not share it with a friend? Or if you have any feedback or just want to say hi, hit reply. I'm always happy to hear from my readers and learn about what you do and how you debug your issues.</em></p>
</div>

<script src="/assets/javascript/prism.js"></script>
</main>

    <footer><div>
  Digital home of
  <a href="https://hamatti.org">Juha-Matti Santala</a> | Built with
  <a href="https://www.11ty.dev/" target="_blank">Eleventy</a> |
  <a href="/feed/feed.xml">RSS</a> | Layout originally by
  <a href="https://html5up.net/">HTML5 UP!</a>
</div>

<nav aria-label="Footer">
  <a href="https://slashpages.net">Slashpages</a>
  <ul>
    <li><a href="/about">/about</a></li>
    <li><a href="/uses">/uses</a></li>
    <li><a href="/colophon">/colophon</a></li>
    <li><a href="/blog/roll">/blogroll</a></li>
    <li><a href="/contact">/contact</a></li>
    <li><a href="/why">/why</a></li>
    <li><a href="/now">/now</a></li>
  </ul>
</nav>

<div>
  <p style="margin: 1em">Trans rights are human rights.</p>
</div>
</footer>

    

    <!-- Dark Mode 

    You can define how you want to style my site by defining
    a light/dark mode setting in your operating system or
    browser settings or by clicking the button at the end of
    the main navigation.

    This Javascript is what manages the button and storing 
    custom configuration.

    -->
    <script src="/assets/javascript/darkmode.js"></script>
  </body>
</html>