Files
nexus/sreweekly/articles/375/05-an-educational-side-project.html
2026-09-12 17:23:01 +08:00

574 lines
52 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>An educational side project - The Pragmatic Engineer</title>
<meta name="HandheldFriendly" content="True" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" href="https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/size/w256h256/2024/06/The-Pragmatic-Engineer-Blog-Publication-Icon--Logo-.png">
<link rel="stylesheet" type="text/css" href="https://blog.pragmaticengineer.com/assets/css/screen.css?v=2YkU7oqFSRPn32Jc" />
<link rel="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Merriweather:300,700,700italic,300italic|Open+Sans:700,400" />
<meta name="description" content="What does a great side project look like, which helps learn new technologies, but also helps stand out when looking for a new job? Analysis of an Uber simulation app, built from scratch.">
<link rel="icon" href="https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/size/w256h256/2024/06/The-Pragmatic-Engineer-Blog-Publication-Icon--Logo-.png" type="image/png">
<link rel="canonical" href="https://blog.pragmaticengineer.com/an-educational-side-project/">
<meta name="referrer" content="no-referrer-when-downgrade">
<meta property="og:site_name" content="The Pragmatic Engineer">
<meta property="og:type" content="article">
<meta property="og:title" content="An educational side project">
<meta property="og:description" content="What does a great side project look like, which helps learn new technologies, but also helps stand out when looking for a new job? Analysis of an Uber simulation app, built from scratch.">
<meta property="og:url" content="https://blog.pragmaticengineer.com/an-educational-side-project/">
<meta property="og:image" content="https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/2023/06/Screenshot-2023-06-01-at-16.09.47-1.png">
<meta property="article:published_time" content="2023-06-01T16:59:39.000Z">
<meta property="article:modified_time" content="2023-06-01T17:11:14.000Z">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="An educational side project">
<meta name="twitter:description" content="What does a great side project look like, which helps learn new technologies, but also helps stand out when looking for a new job? Analysis of an Uber simulation app, built from scratch.">
<meta name="twitter:url" content="https://blog.pragmaticengineer.com/an-educational-side-project/">
<meta name="twitter:image" content="https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/2023/06/Screenshot-2023-06-01-at-16.09.47-1.png">
<meta name="twitter:label1" content="Written by">
<meta name="twitter:data1" content="Gergely Orosz">
<meta name="twitter:site" content="@GergelyOrosz">
<meta name="twitter:creator" content="@GergelyOrosz">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="667">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"publisher": {
"@type": "Organization",
"name": "The Pragmatic Engineer",
"url": "https://blog.pragmaticengineer.com/",
"logo": {
"@type": "ImageObject",
"url": "https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/2015/12/pragmatic-engineer-profile-image.png"
}
},
"author": {
"@type": "Person",
"name": "Gergely Orosz",
"url": "https://blog.pragmaticengineer.com/author/gergely/",
"sameAs": [
"https://x.com/GergelyOrosz"
]
},
"headline": "An educational side project",
"url": "https://blog.pragmaticengineer.com/an-educational-side-project/",
"datePublished": "2023-06-01T16:59:39.000Z",
"dateModified": "2023-06-01T17:11:14.000Z",
"image": {
"@type": "ImageObject",
"url": "https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/size/w1200/2023/06/Screenshot-2023-06-01-at-16.09.47-1.png",
"width": 1200,
"height": 667
},
"description": "What does a great side project look like, which helps learn new technologies, but also helps stand out when looking for a new job? Analysis of an Uber simulation app, built from scratch.",
"mainEntityOfPage": "https://blog.pragmaticengineer.com/an-educational-side-project/"
}
</script>
<meta name="generator" content="Ghost 6.64">
<link rel="alternate" type="application/rss+xml" title="The Pragmatic Engineer" href="https://blog.pragmaticengineer.com/rss/">
<script defer src="https://cdn.jsdelivr.net/ghost/portal@~2.71/umd/portal.min.js" data-i18n="true" data-ghost="https://blog.pragmaticengineer.com/" data-key="e19be39046770b14a9d5caceb0" data-api="https://pragmatic-engineer.ghost.io/ghost/api/content/" data-locale="en" crossorigin="anonymous"></script><style id="gh-members-styles">.gh-post-upgrade-cta-content,
.gh-post-upgrade-cta {
display: flex;
flex-direction: column;
align-items: center;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
text-align: center;
width: 100%;
color: #ffffff;
font-size: 16px;
}
.gh-post-upgrade-cta-content {
border-radius: 8px;
padding: 40px 4vw;
}
.gh-post-upgrade-cta h2 {
color: #ffffff;
font-size: 28px;
letter-spacing: -0.2px;
margin: 0;
padding: 0;
}
.gh-post-upgrade-cta p {
margin: 20px 0 0;
padding: 0;
}
.gh-post-upgrade-cta small {
font-size: 16px;
letter-spacing: -0.2px;
}
.gh-post-upgrade-cta a {
color: #ffffff;
cursor: pointer;
font-weight: 500;
box-shadow: none;
text-decoration: underline;
}
.gh-post-upgrade-cta a:hover {
color: #ffffff;
opacity: 0.8;
box-shadow: none;
text-decoration: underline;
}
.gh-post-upgrade-cta a.gh-btn {
display: block;
background: #ffffff;
text-decoration: none;
margin: 28px 0 0;
padding: 8px 18px;
border-radius: 4px;
font-size: 16px;
font-weight: 600;
}
.gh-post-upgrade-cta a.gh-btn:hover {
opacity: 0.92;
}</style>
<script defer src="https://cdn.jsdelivr.net/ghost/sodo-search@~1.8/umd/sodo-search.min.js" data-key="e19be39046770b14a9d5caceb0" data-styles="https://cdn.jsdelivr.net/ghost/sodo-search@~1.8/umd/main.css" data-sodo-search="https://pragmatic-engineer.ghost.io/" data-locale="en" crossorigin="anonymous"></script>
<link href="https://blog.pragmaticengineer.com/webmentions/receive/" rel="webmention">
<script defer src="/public/cards.min.js?v=ShRHxgy4po8zN-Wf"></script>
<link rel="stylesheet" type="text/css" href="/public/cards.min.css?v=WwnU9jw5ancNC8Gc">
<script defer src="/public/member-attribution.min.js?v=AKG4hWena9j3yX3I"></script>
<script defer src="/public/ghost-stats.min.js?v=vFcCUf6ZQ0Hyhc8h" data-stringify-payload="false" data-datasource="analytics_events" data-storage="localStorage" data-host="https://blog.pragmaticengineer.com/.ghost/analytics/api/v1/page_hit" tb_site_uuid="39f85cc7-8637-40fc-a57c-f45754453717" tb_post_uuid="741bd371-235e-4cd8-92ba-657daf3fb2b5" tb_post_type="post" tb_member_uuid="undefined" tb_member_status="undefined" tb_gift_link=""></script><style>:root {--ghost-accent-color: #15171A;}</style>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/themes/prism.min.css" />
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/plugins/line-numbers/prism-line-numbers.min.css" />
<style>
pre[class*=language-] {
margin: 1.75em 0;
}
</style>
</head>
<body class="post-template nav-closed">
<div class="nav mobile">
<h3 class="nav-title">Menu</h3>
<a href="#" class="nav-close">
<span class="hidden">Close</span>
</a>
<ul>
<li class="nav-home elusive-icon Home" role="presentation"><a href="https://blog.pragmaticengineer.com/">Home</a></li>
<li class="nav-newsletter elusive-icon Newsletter" role="presentation"><a href="https://newsletter.pragmaticengineer.com/about">Newsletter</a></li>
<li class="nav-podcast elusive-icon Podcast" role="presentation"><a href="https://pragmaticpodcast.com">Podcast</a></li>
<li class="nav-sponsors elusive-icon Sponsors" role="presentation"><a href="https://blog.pragmaticengineer.com/sponsors/">Sponsors</a></li>
<li class="nav-ethics-statement elusive-icon Ethics statement" role="presentation"><a href="https://blog.pragmaticengineer.com/ethics-statement/">Ethics statement</a></li>
<li class="nav-now elusive-icon Now" role="presentation"><a href="https://blog.pragmaticengineer.com/now/">Now</a></li>
<li class="nav-my-books elusive-icon My Books" role="presentation"><a href="https://blog.pragmaticengineer.com/books/">My Books</a></li>
<li class="nav-early-trends elusive-icon Early trends" role="presentation"><a href="https://blog.pragmaticengineer.com/early-trends/">Early trends</a></li>
<li class="nav-investing elusive-icon Investing" role="presentation"><a href="https://blog.pragmaticengineer.com/investing/">Investing</a></li>
<li class="nav-contact-me elusive-icon Contact me" role="presentation"><a href="https://blog.pragmaticengineer.com/contact/">Contact me</a></li>
<li class="nav-about elusive-icon About" role="presentation"><a href="https://blog.pragmaticengineer.com/about/">About</a></li>
<li class="nav-rss-feed elusive-icon RSS Feed" role="presentation"><a href="https://blog.pragmaticengineer.com/feed/">RSS Feed</a></li>
<li class="nav-bluesky elusive-icon bluesky" role="presentation"><a href="https://bsky.app/profile/gergely.pragmaticengineer.com/">bluesky</a></li>
<li class="nav-twitter elusive-icon twitter" role="presentation"><a href="http://twitter.com/GergelyOrosz">twitter</a></li>
<li class="nav-youtube elusive-icon youtube" role="presentation"><a href="https://www.youtube.com/@pragmaticengineer">youtube</a></li>
<li class="nav-linkedin elusive-icon linkedin" role="presentation"><a href="http://www.linkedin.com/in/gergelyorosz">linkedin</a></li>
</ul>
<a class="subscribe-button icon-feed" href="https://blog.pragmaticengineer.com/rss/">Subscribe</a>
</div>
<span class="nav-cover mobile"></span>
<div class="nav-desktop">
<ul class="sidebar-nav">
<li class="nav-desktop" role="presentation">
<a href="https://blog.pragmaticengineer.com/" class="elusive-icon Home" rel="me">Home</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://newsletter.pragmaticengineer.com/about" class="elusive-icon Newsletter" rel="me">Newsletter</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://pragmaticpodcast.com" class="elusive-icon Podcast" rel="me">Podcast</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://blog.pragmaticengineer.com/sponsors/" class="elusive-icon Sponsors" rel="me">Sponsors</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://blog.pragmaticengineer.com/ethics-statement/" class="elusive-icon Ethics statement" rel="me">Ethics statement</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://blog.pragmaticengineer.com/now/" class="elusive-icon Now" rel="me">Now</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://blog.pragmaticengineer.com/books/" class="elusive-icon My Books" rel="me">My Books</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://blog.pragmaticengineer.com/early-trends/" class="elusive-icon Early trends" rel="me">Early trends</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://blog.pragmaticengineer.com/investing/" class="elusive-icon Investing" rel="me">Investing</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://blog.pragmaticengineer.com/contact/" class="elusive-icon Contact me" rel="me">Contact me</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://blog.pragmaticengineer.com/about/" class="elusive-icon About" rel="me">About</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://blog.pragmaticengineer.com/feed/" class="elusive-icon RSS Feed" rel="me">RSS Feed</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://bsky.app/profile/gergely.pragmaticengineer.com/" class="elusive-icon bluesky" rel="me">bluesky</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="http://twitter.com/GergelyOrosz" class="elusive-icon twitter" rel="me">twitter</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://www.youtube.com/@pragmaticengineer" class="elusive-icon youtube" rel="me">youtube</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="http://www.linkedin.com/in/gergelyorosz" class="elusive-icon linkedin" rel="me">linkedin</a>
</li>
</ul>
</div>
<div class="site-wrapper">
<header class="main-header post-head " style="background-image: url(https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/2023/06/Screenshot-2023-06-01-at-16.09.47-1.png)">
<nav class="main-nav overlay clearfix">
<a class="blog-logo" href="https://blog.pragmaticengineer.com"><img src="https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/2015/12/pragmatic-engineer-profile-image.png" alt="The Pragmatic Engineer" /></a>
<a class="menu-button icon-menu" href="#"><span class="word">Menu</span></a>
</nav>
</header>
<main class="content" role="main">
<article class="post">
<header class="post-header">
<h1 class="post-title">An educational side project</h1>
</header>
<section class="post-content" id="content">
<!--
<p><em>Before we start: I'm hosting the first-ever <strong><a href="https://www.pragmaticsummit.com/">The Pragmatic Summit</a></strong> on 11 February, 2026, in San Francisco. Join 400 top engineers and leaders as we answer the question: How is AI reshaping software engineering, dev workflows, and the modern engineering stack?
Spaces are limited - don't miss out! <strong><a href="https://www.pragmaticsummit.com/">Buy tickets here</a></strong>.
</em></p>
-->
<p><em>👋 Hi, this is </em><a href="https://twitter.com/gergelyorosz?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow"><em>Gergely</em></a><em> with a bonus, free issue of the Pragmatic Engineer Newsletter. We cover one out of four topics in today’s subscriber-only </em><a href="https://newsletter.pragmaticengineer.com/p/the-scoop-50-why-are-many-snap-employees?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow"><em>The Scoop issue</em></a><em>. If you’re not yet a full subscriber, you missed this week’s deep-dive on </em><a href="https://newsletter.pragmaticengineer.com/p/inside-agodas-private-cloud?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow"><em>Agoda’s private cloud setup</em></a><em>. To get the full issues, twice a week, <a href="https://newsletter.pragmaticengineer.com/about?ref=blog.pragmaticengineer.com">subscribe here</a>.</em></p><p>I’d like to share a story about an educational side project which could prove fruitful for a software engineer who’s seeking a new job.</p><p><a href="https://jurajmajerik.com/?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow">Juraj Majerik</a> is an Amsterdam-based software engineer who decided to improve his applied knowledge of containerization, multiprocessing and observability. So he built a “clone” of a ridesharing app like Uber or Bolt: the app simulates riders requesting trips and drivers picking them up, then repeats this all over again. See it <a href="https://rides.jurajmajerik.com/?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow">in action, here</a>:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/2023/06/Screenshot-2023-06-01-at-16.09.47.png" class="kg-image" alt="A screenshot of the interactive “Rides” app. See the full app here" loading="lazy" width="1936" height="1076" srcset="https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/size/w600/2023/06/Screenshot-2023-06-01-at-16.09.47.png 600w, https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/size/w1000/2023/06/Screenshot-2023-06-01-at-16.09.47.png 1000w, https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/size/w1600/2023/06/Screenshot-2023-06-01-at-16.09.47.png 1600w, https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/2023/06/Screenshot-2023-06-01-at-16.09.47.png 1936w" sizes="(min-width: 720px) 720px"><figcaption><em>A screenshot of the interactive “Rides” app. See the full app </em><a href="https://rides.jurajmajerik.com/?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow"><em>here</em></a></figcaption></figure><p>What grabbed my attention was how this app is much more than just a simulation. Juraj included system monitoring parts which monitor the server’s capacity he runs the app on:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/2023/06/Screenshot-2023-06-01-at-16.12.39.png" class="kg-image" alt="The monitoring page on the Rides app" loading="lazy" width="2000" height="1307" srcset="https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/size/w600/2023/06/Screenshot-2023-06-01-at-16.12.39.png 600w, https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/size/w1000/2023/06/Screenshot-2023-06-01-at-16.12.39.png 1000w, https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/size/w1600/2023/06/Screenshot-2023-06-01-at-16.12.39.png 1600w, https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/2023/06/Screenshot-2023-06-01-at-16.12.39.png 2360w" sizes="(min-width: 720px) 720px"><figcaption>The <a href="https://rides.jurajmajerik.com/monitor?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow">monitoring page</a> on the Rides app</figcaption></figure><p>And it doesn’t end here. Juraj created <a href="https://rides.jurajmajerik.com/system-design?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow">a systems design</a> explainer on how he built this project, and the technologies used:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/2023/06/Screenshot-2023-06-01-at-16.13.53.png" class="kg-image" alt="The systems design diagram for the Rides application" loading="lazy" width="1298" height="1030" srcset="https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/size/w600/2023/06/Screenshot-2023-06-01-at-16.13.53.png 600w, https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/size/w1000/2023/06/Screenshot-2023-06-01-at-16.13.53.png 1000w, https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/2023/06/Screenshot-2023-06-01-at-16.13.53.png 1298w" sizes="(min-width: 720px) 720px"><figcaption>The systems design diagram for the Rides application</figcaption></figure><p>The app uses:</p><ul><li><strong>Node.js</strong> for the simulation engine</li><li><strong>Go</strong> on the backend</li><li><strong>PostgreSQL</strong> for the data layer</li><li><strong>React</strong> and <strong>TypeScript</strong> on the frontend</li><li><strong>Prometheus</strong> and <strong>Grafana</strong> for monitoring and observability</li></ul><p>And if you were wondering how all of this was built, Juraj documented his process in an incredible, 34-part blog series. You can <a href="https://jurajmajerik.com/?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow">read this here</a>.</p><p><strong>This “Uber clone” offers a nice blueprint on how to tackle a complicated project</strong>. Thanks to the detailed documentation of Juraj’s progress, we can reconstruct how he built the project. This is educational, as it shows one possible way to tackle a complicated project, and one for which the creator could only devote time to on the side, and at weekends. Here’s how Juraj approached the undertaking:</p><p><strong>Phase 0: make a plan (Oct)</strong>. Instead of starting with coding, Juraj kicked off by sketching. He sketched out what he wanted the final product to look like:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/2023/06/Screenshot-2023-06-01-at-16.34.54.png" class="kg-image" alt="The sketch Juraj made, before starting any coding" loading="lazy" width="1256" height="878" srcset="https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/size/w600/2023/06/Screenshot-2023-06-01-at-16.34.54.png 600w, https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/size/w1000/2023/06/Screenshot-2023-06-01-at-16.34.54.png 1000w, https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/2023/06/Screenshot-2023-06-01-at-16.34.54.png 1256w" sizes="(min-width: 720px) 720px"><figcaption>The sketch Juraj made, before starting any coding</figcaption></figure><p>And he sketched how he envisioned the observability part to work:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/2023/06/Screenshot-2023-06-01-at-16.34.59.png" class="kg-image" alt="The sketch of the monitoring system" loading="lazy" width="1260" height="556" srcset="https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/size/w600/2023/06/Screenshot-2023-06-01-at-16.34.59.png 600w, https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/size/w1000/2023/06/Screenshot-2023-06-01-at-16.34.59.png 1000w, https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/2023/06/Screenshot-2023-06-01-at-16.34.59.png 1260w" sizes="(min-width: 720px) 720px"><figcaption><em>The sketch of the monitoring system</em></figcaption></figure><p><strong>Phase 1: Infrastructure (October-November)</strong>.</p><p>Before diving into coding, Juraj set up the infrastructure. I assume he did this to familiarize himself with infrastructure which he hasn’t necessarily used in production before. This side project offered a good opportunity to try it out.</p><ol><li>Set up a server on DigitalOcean (a virtual machine with 1GB memory and 25GB of disk space)</li><li>Set up the domain, and configure the DNS</li><li>Set up users on the server</li><li>Set up SSH keys for more secure authentication</li><li>Install Go on the server, which will power much of the backend</li><li>Set up a HTTP server using Go</li><li>Deploy for the first time, doing so manually, for now</li><li>Enable HTTPS by registering a certificate</li><li>Utilize environment variables to be used for configuration, instead of hardcoding configuration or secrets into the source code. Hardcoding secrets in production is poor practice. <em>We </em><a href="https://newsletter.pragmaticengineer.com/i/123763637/a-month-code-freeze-at-stackoverflow?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow"><em>covered</em></a><em> how Stack Overflow learned this the hard way, a few months back.</em></li><li>Serving a web page. This is the point where the app reached the “Hello world!” stage</li><li>Improve deploys. Change deploys to be a one-command process, instead of multiple steps</li></ol><p><em>See </em><a href="https://jurajmajerik.com/?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow"><em>blog posts #1-11</em></a><em> for details on all the steps.</em></p><p><strong>Phase 2: some business logic, and more infra (December-January)</strong></p><ol><li>Draw a map using JavaScript to map onto an <a href="https://en.wikipedia.org/wiki/SVG?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow">SVG</a> format</li><li>Build a graph and traverse it. <a href="https://jurajmajerik.com/blog/build-graph/?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow">Here’s a video</a> of Juraj demonstrating this traversal.</li><li>Set up Docker to package the application into containers</li><li>Use Docker in production, and modify the deploy script to deploy using Docker</li><li>Set up PostgreSQL to persist data on drivers, riders and trips</li><li>Connect the Go backend to the PostgreSQL database</li><li>Connect the backend and the database containers</li><li><a href="https://docs.docker.com/compose/?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow">Docker Compose</a> in production</li></ol><p><em>See </em><a href="https://jurajmajerik.com/?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow"><em>blog posts #12-20</em></a><em> for details on all the steps.</em></p><p><strong>Phase 3: a basic UX (February)</strong></p><ol><li>Migrate to React</li><li>Design a car, from a vector image</li><li>Move a car with animations. Including adding unit tests.</li><li>Turn a car using rotations</li><li>Tidying up the project: refactoring the files now, that the project’s structure is more clear</li><li>Server-generated data</li><li>Animation fixes</li></ol><p><em>See </em><a href="https://jurajmajerik.com/?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow"><em>blog posts #21-27</em></a><em> for details on all the steps.</em></p><p><strong>Phase 4: “hardcore” coding (March)</strong></p><p>This was the first phase where Juraj did no more infrastructure work, and focused only on “pure” business logic.</p><ul><li>Simulation engine: this component simulates the behavior of drivers and customers</li><li>Multiprocessing for Node.js, to avoid blocking the event loop</li><li>Generating destinations, and making sure the start point is not too close to the destination</li><li>Matching drivers with customers: doing this similarly to how a service like Uber does</li><li>Route planner: tell the driver which route to choose to collect a  customer</li></ul><p><em>See </em><a href="https://jurajmajerik.com/?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow"><em>blog posts #28-32</em></a><em> for details on all the steps.</em></p><p><strong>Phase 5: finalizing and monitoring (April)</strong></p><ul><li>Finalizing the simulation</li><li>Setting up monitoring &amp; logging</li></ul><p><em>See </em><a href="https://jurajmajerik.com/?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow"><em>blog posts #33 &amp; 34</em></a><em> for details of all the steps.</em></p><h3 id="standoud-things-about-this-side-project">Standoud things about this side project</h3><p>There are several things that I’ll highlight about this side project.</p><p><strong>1. Persistence. </strong>Juraj built this project on the side, between October 2022 and April 2023, which is 7 months.</p><p><strong>2. Documenting the steps. </strong>Every time Juraj made progress, he documented what he did, and how. This likely helped him to learn, and it also helps others wanting to understand, too.</p><p><strong>3. Incremental progress.</strong> The project looks like a tough one to build from scratch on the side. But looking at the incremental steps, it is not nearly so daunting. Here are a few of the steps, taken directly from the blog:</p><ul><li>Monday: <a href="https://jurajmajerik.com/blog/golang-installation/?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow">installing Go</a> on the server (17 Oct)</li><li>Wednesday: <a href="https://jurajmajerik.com/blog/golang-installation/?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow">setting up the HTTP server</a> using Node’s native http module (19 Oct)</li><li>Friday: <a href="https://jurajmajerik.com/blog/first-deployment/?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow">the first deploy</a> (21 Oct)</li><li>Saturday: <a href="https://jurajmajerik.com/blog/using-https/?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow">enabling HTTPs</a> (22 Oct)</li><li>Sunday: <a href="https://jurajmajerik.com/blog/environment-variables/?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow">setting up environment variables</a> (23 Oct)</li><li>(Step away from the side project for a week)</li><li>…then do another burst of tasks, making more progress</li></ul><p><strong>4. You won’t get the layout of a project right, the first time. So refactor! </strong>Juraj was about 70% done with the project, when he went back to refactor the structure of the project. This wasn’t for the lack of planning: but because as you set up new infrastructure, things turn out a bit different than you expected.</p><p>This is just the way of software engineering, and there’s nothing to be embarrassed about it. As you learn more about the project, don’t be afraid to go back and change the project structure – or do other refactorings – to help your work, going forward. See <a href="https://jurajmajerik.com/blog/tidying-up/?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow">the project structure</a> Juraj set up at the end of Phase 3.</p><p><strong>5. Infrastructure is important, and setting it up right can be a consuming task!</strong> In the first 3 phases of the project, Juraj spent a <em>lot</em> of time on infrastructure setup. It was only in Phase 4 that he was able to focus “purely” on the coding part.</p><p>I really like how this project showcases <em>just</em> <em>how much time</em> can go into infrastructure setup. At companies with dedicated platform teams, those teams take exactly this kind of load off other teams building greenfield projects.</p><p>Both as an engineer, and especially as an engineering manager, don’t forget there’s a real cost to setting up and then maintaining infrastructure. Much infrastructure work is invisible as it does not involve commits, and most engineers won’t document the time they spend on these tasks, like Juraj has. But this is work that still needs to be done!</p><p><strong>Here are the learnings Juraj had with this project. </strong>I reached out to Juraj to ask how this project helped him. His answer:</p><blockquote>“I've touched on many topics I haven't been exposed to in my day-to-day job, such as server configuration, setting up a deployment pipeline, animations in JavaScript, or using Docker. <br><br>I decided to get better at algorithms and data structures a few months ago, and this project complemented it nicely. For example, I implemented the map and its associated methods (e.g. path-finding) from scratch.<br><br>I also wanted to get better at setting up a full-stack project from scratch and understand why certain technologies are used. Docker is a good example - I didn't use it because I ‘wanted to’, but because the necessity for it arose. I was surprised how much time all of the infra work took me before I was able to start with the actual simulation logic!”</blockquote><p>And how did Juraj find the time to work this much on the project?</p><blockquote>“While I was at my previous job, I dedicated 1-2 hours a day, usually after work. After leaving in March due to a layoff, I decided not to start my job search immediately, but spent some more time finishing and polishing this project. That's when I really ramped up my effort on it and started seeing a lot of progress.”</blockquote><p>If you are thinking of doing a side project with the goal of learning new technologies – and, to also be able to share those learnings, and show off the side project – I can recommend taking inspiration from this methodological approach Juraj took. Of course: don’t copy the exact approach, as-is. But planning first, documenting steps, and building a “production simulation” are all ideas that you could use in your own side projects as well. If you do: your side project will surely stand out from many of the other ones.</p><p><strong>Your own projects often seem less impressive to you than they are to others. </strong>I was impressed by the implementation and attention to detail for this project – for example, going the extra mile for adding in monitoring for the server components: typical for a production service, but rarely seen in a side project. When I shared that I’m impressed with the execution with Juraj, his response was surprising, as he told me:</p><blockquote>“Working on this side project every day, it no longer feels that impressive to me (as I think is common with software projects). But having read your fresh perspective, it certainly gives a lot of encouragement!”</blockquote><p>When it’s day-to-day work, most engineers don’t think they’re doing anything complex, or special. And, in all fairness: no single step in Juraj’s project was complex. The complexity comes from the combination of simple steps. This is the beauty of software engineering: that everything that seems complex can be broken down to simple to understand – and simple to implement – steps.</p><p><em>Thanks a lot to Juraj for sharing this project with me. View the complete source code </em><a href="https://github.com/jurajmajerik/rides?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow"><em>here</em></a><em>. If you are hiring for full-stack engineers, Juraj is on the market – at least for now! Connect with him via </em><a href="https://jurajmajerik.com/?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow"><em>his website</em></a><em>, </em><a href="https://www.linkedin.com/in/jurajmajerik/?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow"><em>on LinkedIn</em></a><em> or </em><a href="https://twitter.com/JurajMajerik?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow"><em>on Twitter</em></a><em>.</em></p><hr><p>This was one out of the four topics covered in this week’s The Scoop. A lot of what I share in The Scoop is exclusive to this publication, meaning it’s not been covered in any other media outlet before and you’re the first to read about it.</p><p>The full The Scoop edition additionally covers:</p><ul><li><strong>Why are many Snap employees selling their stock as soon as it vests, and not a day later? </strong>Snap is a very strange publicly traded company, where shareholders have precisely zero votes. I’ve talked with engineers and discovered a surprising level of distrust within the company. Is this tied to the governance model, or something else? <strong><em>Exclusive</em></strong>.</li><li><strong>Analyzing the split of cuts at Lyft. </strong>How much were software engineers impacted by ride-hailing service Lyft’s large-scale cuts? I went through data based on Lyft’s talent directory; it looks like tech functions were hit harder than other areas. <strong><em>Exclusive</em></strong>.</li><li><strong>Robinhood is no longer a remote-first company. </strong>Few companies were as vocal about becoming a remote-first company than Robinhood. But less than 18 months later, the company has made a u-turn. What can founders and leaders take from this avoidable policy reversal? <em>Analysis</em>.</li></ul><p><a href="https://newsletter.pragmaticengineer.com/p/the-scoop-50-why-are-many-snap-employees?ref=blog.pragmaticengineer.com" rel="noopener noreferrer nofollow">Read the full The Scoop here.</a></p>
<!-- Newsletter -->
<p>
<a href="https://newsletter.pragmaticengineer.com/about">Subscribe to my weekly newsletter</a> to get articles like this in your inbox. It's a pretty good read - and the <a href="https://substack.com/top/technology">#1 software engineering newsletter</a> on Substack.
</p>
</section>
<footer class="post-footer">
<section class="podcast-details">
<h4>The Pragmatic Engineer Podcast</h4>
<p>
Deepdives with experienced engineers and tech professionals who share their hard-earned lessons, interesting stories and advice they have on building software.
</p>
<p>
Listen to it <a href="https://open.spotify.com/show/2Bho9xCbOQMWMJ7UKmqCzD">on Spotify</a>, on <a href="https://podcasts.apple.com/us/podcast/the-pragmatic-engineer/id1769051199">Apple</a>, on <a href="https://www.youtube.com/@pragmaticengineer">YouTube</a>, or <a href="https://pragmaticpodcast.com/">on the web</a>.
</p>
</section>
<section class="book-details">
<h4>The Software Engineer's Guidebook</h4>
<p>
I wrote <a href="https://www.engguidebook.com/">The Software Engineer's Guidebook</a>. Here is what Tanya Reilly, senior principal engineer and author of <a href="https://www.oreilly.com/library/view/the-staff-engineers/9781098118723/">The Staff Engineer's Path</a> says about it:
</p>
<blockquote>
"From performance reviews to P95 latency, from team dynamics to testing, Gergely demystifies all aspects of a software career. This book is well named: <strong>it really does feel like the missing guidebook for the whole industry.</strong>"
</blockquote>
<p style="padding-top:20px">
<a href="https://www.engguidebook.com/">
<img src="/assets/img/EngGuidebook.jpg" alt="The Software Engineer's Guidebook" style="width: 100%; max-width: 300px; margin: 0 auto; display: block;"/>
</a>
</p>
<p>
<a href="https://www.engguidebook.com/">Get the book here.</a>
</p>
</section>
<section class="conference-details">
<h4>Annual conference talk</h4>
<p>
Every year, I do one conference talk in the US, and one in Europe. <strong>My next conference talk is at <a href="https://leaddev.com/leaddev-new-york/?utm_source=pragmaticengineer&utm_medium=email&utm_campaign=pragmaticengineer">LDX3 New York</a>, on 15 September 2026.</strong>
Previous talks:
</p>
<ul>
<li><a href="https://newsletter.pragmaticengineer.com/p/slow-down-to-speed-up">Slow down to speed up</a> - Craft Conference, 2026</li>
<li><a href="https://newsletter.pragmaticengineer.com/p/software-engineering-with-llms-in-2025">Software engineering with LLMs: reality check</a> - LDX3, London, 2025</li>
</ul>
<p>
<strong>
</strong>
</p>
<!--
In 2025, this will be at <a href="https://leaddev.com/leaddev-london/?utm_source=the-pragmatic-engineer&utm_medium=newsletter-social&utm_campaign=LON25-media-community-partner">LDX3 (formerly: LeadDev)</a> in London, 16 June 2025. My keynote is titled "Software engineering with GenAI." If you'll <a href="https://leaddev.com/leaddev-london/?utm_source=the-pragmatic-engineer&utm_medium=newsletter-social&utm_campaign=LON25-media-community-partner">be there</a>, come say hi!
-->
</section>
<section class="newsletter" id="newsletter-second"> <!-- Section that gets moved up -->
<h4>Newsletter</h4>
<p>
Enjoying this article? <a href="https://newsletter.pragmaticengineer.com/about">Subscribe to my newsletter</a> to get issues like this in your inbox. It's a good read and the <a href="https://substack.com/top/technology">#1 software engineering / AI engineering newsletter</a> on Substack.
</p>
</section>
<section class="authorAndShare">
<section class="author">
<h4><a href="/author/gergely/">Gergely Orosz</a></h4>
<section class="post-meta">
Last updated <time class="post-date" datetime="2023-06-01">01 June 2023</time>. Originally published 01 Jun 2023.
<br>&copy; Gergely Orosz, 2023
</section>
<p>Writing The Pragmatic Engineer Newsletter. Author of The Software Engineer&#x27;s Guidebook. Previously at Uber, Microsoft, Skype, Skyscanner.</p>
<div class="author-meta">
<span class="author-location icon-location">Amsterdam, Netherlands</span>
</div>
</section>
<section class="share">
<h4>Share this post</h4>
<a class="icon-twitter" href="https://twitter.com/intent/tweet?text=An%20educational%20side%20project&amp;url=https://blog.pragmaticengineer.com/an-educational-side-project/"
onclick="window.open(this.href, 'twitter-share', 'width=550,height=235');return false;">
<span class="hidden">Twitter</span>
</a>
<a class="icon-facebook" href="https://www.facebook.com/sharer/sharer.php?u=https://blog.pragmaticengineer.com/an-educational-side-project/"
onclick="window.open(this.href, 'facebook-share','width=580,height=296');return false;">
<span class="hidden">Facebook</span>
</a>
</section>
<section>
</footer>
</article>
</main>
<aside class="sidebar">
<img class="profile-image" src="https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/2015/12/pragmatic-engineer-profile-image.png" alt="" />
<!--
// to display a custom image, copy the image into assets/img/profile-img.png and replace the previous line with this:
<img class="profile-image" src="https://blog.pragmaticengineer.com/assets/img/profile-image.png?v=0ccd6679d9" alt="" />
-->
<section class="publisher">by <strong>Gergely Orosz</strong></section>
<div class="nav mobile">
<h3 class="nav-title">Menu</h3>
<a href="#" class="nav-close">
<span class="hidden">Close</span>
</a>
<ul>
<li class="nav-home elusive-icon Home" role="presentation"><a href="https://blog.pragmaticengineer.com/">Home</a></li>
<li class="nav-newsletter elusive-icon Newsletter" role="presentation"><a href="https://newsletter.pragmaticengineer.com/about">Newsletter</a></li>
<li class="nav-podcast elusive-icon Podcast" role="presentation"><a href="https://pragmaticpodcast.com">Podcast</a></li>
<li class="nav-sponsors elusive-icon Sponsors" role="presentation"><a href="https://blog.pragmaticengineer.com/sponsors/">Sponsors</a></li>
<li class="nav-ethics-statement elusive-icon Ethics statement" role="presentation"><a href="https://blog.pragmaticengineer.com/ethics-statement/">Ethics statement</a></li>
<li class="nav-now elusive-icon Now" role="presentation"><a href="https://blog.pragmaticengineer.com/now/">Now</a></li>
<li class="nav-my-books elusive-icon My Books" role="presentation"><a href="https://blog.pragmaticengineer.com/books/">My Books</a></li>
<li class="nav-early-trends elusive-icon Early trends" role="presentation"><a href="https://blog.pragmaticengineer.com/early-trends/">Early trends</a></li>
<li class="nav-investing elusive-icon Investing" role="presentation"><a href="https://blog.pragmaticengineer.com/investing/">Investing</a></li>
<li class="nav-contact-me elusive-icon Contact me" role="presentation"><a href="https://blog.pragmaticengineer.com/contact/">Contact me</a></li>
<li class="nav-about elusive-icon About" role="presentation"><a href="https://blog.pragmaticengineer.com/about/">About</a></li>
<li class="nav-rss-feed elusive-icon RSS Feed" role="presentation"><a href="https://blog.pragmaticengineer.com/feed/">RSS Feed</a></li>
<li class="nav-bluesky elusive-icon bluesky" role="presentation"><a href="https://bsky.app/profile/gergely.pragmaticengineer.com/">bluesky</a></li>
<li class="nav-twitter elusive-icon twitter" role="presentation"><a href="http://twitter.com/GergelyOrosz">twitter</a></li>
<li class="nav-youtube elusive-icon youtube" role="presentation"><a href="https://www.youtube.com/@pragmaticengineer">youtube</a></li>
<li class="nav-linkedin elusive-icon linkedin" role="presentation"><a href="http://www.linkedin.com/in/gergelyorosz">linkedin</a></li>
</ul>
<a class="subscribe-button icon-feed" href="https://blog.pragmaticengineer.com/rss/">Subscribe</a>
</div>
<span class="nav-cover mobile"></span>
<div class="nav-desktop">
<ul class="sidebar-nav">
<li class="nav-desktop" role="presentation">
<a href="https://blog.pragmaticengineer.com/" class="elusive-icon Home" rel="me">Home</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://newsletter.pragmaticengineer.com/about" class="elusive-icon Newsletter" rel="me">Newsletter</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://pragmaticpodcast.com" class="elusive-icon Podcast" rel="me">Podcast</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://blog.pragmaticengineer.com/sponsors/" class="elusive-icon Sponsors" rel="me">Sponsors</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://blog.pragmaticengineer.com/ethics-statement/" class="elusive-icon Ethics statement" rel="me">Ethics statement</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://blog.pragmaticengineer.com/now/" class="elusive-icon Now" rel="me">Now</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://blog.pragmaticengineer.com/books/" class="elusive-icon My Books" rel="me">My Books</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://blog.pragmaticengineer.com/early-trends/" class="elusive-icon Early trends" rel="me">Early trends</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://blog.pragmaticengineer.com/investing/" class="elusive-icon Investing" rel="me">Investing</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://blog.pragmaticengineer.com/contact/" class="elusive-icon Contact me" rel="me">Contact me</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://blog.pragmaticengineer.com/about/" class="elusive-icon About" rel="me">About</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://blog.pragmaticengineer.com/feed/" class="elusive-icon RSS Feed" rel="me">RSS Feed</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://bsky.app/profile/gergely.pragmaticengineer.com/" class="elusive-icon bluesky" rel="me">bluesky</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="http://twitter.com/GergelyOrosz" class="elusive-icon twitter" rel="me">twitter</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="https://www.youtube.com/@pragmaticengineer" class="elusive-icon youtube" rel="me">youtube</a>
</li>
<li class="nav-desktop" role="presentation">
<a href="http://www.linkedin.com/in/gergelyorosz" class="elusive-icon linkedin" rel="me">linkedin</a>
</li>
</ul>
</div>
<ul>
<li><a href="https://blog.pragmaticengineer.com/newsletter" class="elusive-icon email">Subscribe via email</a></li>
<li><a href="http://feeds.feedburner.com/ThePragmaticEngineer" class="elusive-icon rss">Subscribe in a reader</a></li>
</ul>
<footer class="site-footer clearfix">
<section class="copyright"><a href="https://blog.pragmaticengineer.com">The Pragmatic Engineer</a> &copy; 2023</section>
</footer>
</aside>
<aside class="read-next">
<a class="read-next-story " style="background-image: url(https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/2023/06/Screenshot-2023-06-08-at-17.50.37-1.png)" href="/should-you-optimize-for-all-cash-compensation/">
<section class="post">
<h2>Should you optimize for all-cash compensation, if possible?</h2>
<p>Although still rare in the industry, companies like Netflix and Shopify let employees choose how much of their total compensation is stock. What are the approaches to take?&hellip;</p>
</section>
</a>
<a class="read-next-story prev " style="background-image: url(https://storage.ghost.io/c/39/f8/39f85cc7-8637-40fc-a57c-f45754453717/content/images/2023/05/Screenshot-2023-05-25-at-20.20.13-1.png)" href="/layoffs-push-down-scores-on-glassdoor/">
<section class="post">
<h2>Layoffs push down scores on Glassdoor: this is how companies respond</h2>
<p>Several tech companies face a fresh problem after cutting jobs: their rating on Glassdoor nosedives. But there’s a way they can fix this. I show what companies are doing - and why.&hellip;</p>
</section>
</a>
</aside>
<!-- Signup move up -->
<script>
let contentParent = document.getElementById("content");
let newsletterWithFormElement = document.getElementById("newsletter");
let newsletterWithoutFormElement = document.getElementById("newsletter-second");
let newsLetterTargetPosition = getLastElementBeforeSpecificNode(contentParent.children, "H2", 2); // Add after the 2nd h2
if(contentParent.children.length > newsLetterTargetPosition) {
let nextSibling = contentParent.children[newsLetterTargetPosition];
contentParent.insertBefore(newsletterWithoutFormElement, nextSibling);
} else {
newsletterWithoutFormElement.style.display = "none"
}
function getLastElementBeforeSpecificNode(nodes, nodeName, numberOfNodesToPass) {
var numberOfSpecificNodessSeen = 0;
for(let i=0;i<nodes.length; i++) {
if(nodes[i].nodeName == nodeName) {
numberOfSpecificNodessSeen += 1;
}
if(numberOfSpecificNodessSeen == numberOfNodesToPass+1) {
if(i > 0) {
return i;
} else {
return nodes.lenght;
}
}
}
}
</script>
</div>
<!-- Geniuslink -->
<!--
<script type="text/javascript" src="//cdn.geni.us/snippet.min.js" defer></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function() {
var tsid =116191;
Genius.amazon.addOnClickRedirect(tsid, false, "https://buy.geni.us"); });
</script>-->
<!-- Google Analytics -->
<!--
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-7745037-4', 'auto');
ga('send', 'pageview');
</script>
-->
<!-- Plausible -->
<script async defer data-domain="blog.pragmaticengineer.com" src="https://plausible.io/js/plausible.js"></script>
<!-- Source code higlighting -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/prism.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/plugins/line-numbers/prism-line-numbers.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/components/prism-javascript.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/components/prism-css.min.js"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script type="text/javascript" src="https://blog.pragmaticengineer.com/assets/js/jquery.fitvids.js?v=z1Nmfc9MKQxCtlIV"></script>
<script type="text/javascript" src="https://blog.pragmaticengineer.com/assets/js/index.js?v=wmn33DUYd3qPYenJ"></script>
</body>
</html>