<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ lessons learned - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ lessons learned - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 25 May 2026 05:06:39 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/lessons-learned/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ What I Learned from Maintaining a Repo During Hacktoberfest and Merging 356 PRs ]]>
                </title>
                <description>
                    <![CDATA[ Hacktoberfest is a month long celebration of open source. And this year I participated as a maintainer for freeCodeCamp's Developer Quiz Site. I merged a total of 356 pull requests and helped a lot of new contributors get started with open source. We... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-i-learned-as-a-hacktoberfest-repo-maintainer/</link>
                <guid isPermaLink="false">66b8da66eb5c4db85a0b3444</guid>
                
                    <category>
                        <![CDATA[ freeCodeCamp.org ]]>
                    </category>
                
                    <category>
                        <![CDATA[ hacktoberfest ]]>
                    </category>
                
                    <category>
                        <![CDATA[ lessons learned ]]>
                    </category>
                
                    <category>
                        <![CDATA[ open source ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Jessica Wilkins ]]>
                </dc:creator>
                <pubDate>Wed, 02 Nov 2022 16:17:06 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/11/Screen-Shot-2022-10-31-at-5.56.25-PM.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hacktoberfest is a month long celebration of open source. And this year I participated as a maintainer for <a target="_blank" href="https://github.com/freeCodeCamp/Developer_Quiz_Site">freeCodeCamp's Developer Quiz Site</a>.</p>
<p>I merged a total of 356 pull requests and helped a lot of new contributors get started with open source. We were able to add a total of 477 new quiz questions to the <a target="_blank" href="https://developerquiz.org/">Developer Quiz Site</a>. </p>
<p>Here are some more statistics: </p>
<h3 id="heading-stats-on-oct-1-2022">Stats on Oct 1, 2022</h3>
<p>Number of questions: 694</p>
<p>Forks: 61</p>
<p>Stars:42</p>
<h3 id="heading-stats-on-november-1-2022">Stats on November 1, 2022</h3>
<p>Number of questions: 1171</p>
<p>Forks: 246</p>
<p>Stars: 109</p>
<p>This month long journey has been crazy, productive, fun and educational. Here are all of the things that I learned during Hacktoberfest 2022.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-how-it-all-began">How it all began</a></li>
<li><a class="post-section-overview" href="#heading-preparing-for-hacktoberfest">Preparing for Hacktoberfest</a><ul>
<li><a class="post-section-overview" href="#heading-step-1-adding-the-hacktoberfest-topic-and-labels">Step 1: Adding the Hacktoberfest topic and labels</a></li>
<li><a class="post-section-overview" href="#heading-step-2-creating-issue-templates">Step 2: Creating issue templates</a></li>
<li><a class="post-section-overview" href="#heading-step-3-updating-the-contributing-documentation">Step 3: Updating the contributing documentation</a></li>
<li><a class="post-section-overview" href="#heading-step-4-creating-well-defined-issues">Step 4: Creating well-defined issues</a></li>
<li><a class="post-section-overview" href="#heading-step-5-adding-saved-replies">Step 5: Adding Saved replies</a></li>
<li><a class="post-section-overview" href="#heading-step-6-opening-up-github-discussions">Step 6: Opening up GitHub Discussions</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-lessons-i-learned-during-hacktoberfest">Lessons I learned during Hacktoberfest</a><ul>
<li><a class="post-section-overview" href="#heading-lead-with-patience-empathy-and-kindness">Lead with patience, empathy and kindness</a></li>
<li><a class="post-section-overview" href="#dont-get-worked-up-over-spam">Don't get worked up over spam</a></li>
<li><a class="post-section-overview" href="#how-to-gracefully-close-prs-that-will-not-be-accepted">How to gracefully close PR's that will not be accepted</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<h2 id="heading-how-it-all-began">How it All Began</h2>
<p>In December of 2021, freeCodeCamp was launching their <a target="_blank" href="https://www.freecodecamp.org/news/learn-to-code-rpg/">Learn to Code RPG game</a>. It's an interactive visual novel that follows Lydia's dream of becoming a developer. </p>
<p>I was involved with helping to create quiz questions on topics like HTML, CSS, Computer Science, Python, and so on for the initial launch. </p>
<p>About a week before the launch, Quincy approached me and a few others to build out a <a target="_blank" href="https://developerquiz.org/">Developer Quiz Site</a>. This was meant to be a companion site to the <a target="_blank" href="https://www.freecodecamp.org/news/learn-to-code-rpg/">Learn to Code RPG game</a> and provide campers with a way to practice more quiz questions outside of the game. </p>
<p>The initial launch of the <a target="_blank" href="https://developerquiz.org/">Developer Quiz Site</a> had about 600+ quiz questions. We also created a few open issues in the <a target="_blank" href="https://github.com/freeCodeCamp/Developer_Quiz_Site">repository</a> for the community to add more questions to the site. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screen-Shot-2022-10-31-at-6.11.55-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>During parts of 2022, there was a moderate amount of activity in the repository but a lot of the time it remained rather slow. But once September rolled around, I thought about entering the <a target="_blank" href="https://developerquiz.org/">Developer Quiz Site</a> into Hacktoberfest.</p>
<p>I reached out to Quincy and he thought it was a great idea because we could use this opportunity to get more quiz questions from the community.</p>
<h2 id="heading-preparing-for-hacktoberfest">Preparing for Hacktoberfest</h2>
<p>There were about 3 weeks left before Hacktoberfest started. Here is how I used that time to get the repository ready.</p>
<h3 id="heading-step-1-adding-the-hacktoberfest-topic-and-labels">Step 1: Adding the Hacktoberfest topic and labels</h3>
<p>The first step was to add the Hacktoberfest topic to the repository so people knew we were participating in this year's event. I spruced up the About section and added the appropriate labels to help invite people to the repository. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screen-Shot-2022-10-31-at-6.41.14-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>I then made sure to create the <code>hacktoberfest-accepted</code> label so I could apply it to each approved PR to help us keep track of the total number of Hacktoberfest PR's. I also added the <code>spam</code>, <code>hacktoberfest</code>, and <code>first-timers-only</code> labels because I knew they would come in handy. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screen-Shot-2022-10-31-at-6.45.45-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-step-2-creating-issue-templates">Step 2: Creating issue templates</h3>
<p><a target="_blank" href="https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository">GitHub issue templates</a> are a great way to ensure that contributors provide all of the necessary information for bug fixes, documentation changes, feature requests or general issues.  </p>
<p>I decided to setup 5 issue categories and make certain fields required so contributors would provide some level of detail to the issues they were creating.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screen-Shot-2022-10-31-at-6.57.28-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screen-Shot-2022-10-31-at-6.53.25-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-step-3-updating-the-contributing-documentation">Step 3: Updating the contributing documentation</h3>
<p>When the repository was initially created, the contributing documentation pointed to the <a target="_blank" href="https://contribute.freecodecamp.org./#/">general freeCodeCamp contributing guidelines</a>. While that documentation is very thorough, it wasn't specific enough on how people could best contribute to the <a target="_blank" href="https://github.com/freeCodeCamp/Developer_Quiz_Site">Developer Quiz site repository</a> in particular. </p>
<p>I decided to completely overhaul the documentation and create a new in depth file just for the Developer Quiz Site. Since I anticipated that we would have a lot of beginners with Git and GitHub, I tried to make it as accessible and beginner friendly as possible.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screen-Shot-2022-10-31-at-7.08.50-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-step-4-creating-well-defined-issues">Step 4: Creating well-defined issues</h3>
<p>In order to attract contributors to our repository, I knew that we needed to have some clearly defined issues. If the issues were too vague, then I knew people would have tons of questions or might not be interested in contributing.</p>
<p>I made sure to include all of the necessary guidelines for submission, including code snippets for the proper formatting, links to the Code of Conduct, Contributing docs, and links to the files they needed to change. </p>
<p>Here is an example of one of the issues I created to encourage more JavaScript questions.</p>
<h4 id="heading-sample-issue">Sample issue</h4>
<p><a target="_blank" href="developerquiz.org">developerquiz.org</a> currently has over 600 quiz questions. We are looking to expand on the JavaScript questions and we encourage other developers to add their quiz questions to the site.</p>
<p><strong>Please note: we are only focusing on general JavaScript questions instead of library and framework specific questions.</strong></p>
<p>You can find the complete list of questions below.
https://github.com/freeCodeCamp/Developer_Quiz_Site/blob/main/src/data/javascript-quiz.ts</p>
<p>You can add your own questions to the top of that file.
<strong>Please first check to make sure your question doesn't already exist in the file before creating a PR.</strong></p>
<p>Here is an example format for the questions. </p>
<pre><code>  {
    <span class="hljs-attr">Question</span>:
      <span class="hljs-string">"In JavaScript, what is the name of the method used to remove white space from the beginning and end of a string?"</span>,
    <span class="hljs-attr">Answer</span>: <span class="hljs-string">".trim()"</span>,
    <span class="hljs-attr">Distractor1</span>: <span class="hljs-string">".substring()"</span>,
    <span class="hljs-attr">Distractor2</span>: <span class="hljs-string">".reduce()"</span>,
    <span class="hljs-attr">Distractor3</span>: <span class="hljs-string">".slice()"</span>,
    <span class="hljs-attr">Explanation</span>:
      <span class="hljs-string">"The .trim() method removes white space (including space, tab, etc.) from both ends of a string and returns a new string without modifying the original."</span>,
    <span class="hljs-attr">Link</span>: <span class="hljs-string">"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim"</span>,
  },
</code></pre><p>For the <code>link</code> field, please make sure to use a freeCodeCamp article, freeCodeCamp YouTube video, or official documentation.
If you choose to reference a video, please make sure to include the timestamp for the topic covered.</p>
<p>You can read more about how to create timestamps in this <a target="_blank" href="https://www.lifewire.com/link-to-specific-part-of-youtube-video-1616414#">helpful article</a>. </p>
<p>This issue will not be assigned to anyone and will remain open for multiple contributors. </p>
<p><strong>Please do not assign yourself to this issue or close it.</strong></p>
<p>Happy contributing!</p>
<p>For most of our issues, I wanted multiple contributors to be able to participate. So I added a disclaimer at the bottom letting people know that it would remain open and wouldn't be assigned to anyone. </p>
<p>I also made sure to add the <code>good-first-issue</code>, <code>help-wanted</code>, and <code>hacktoberfest</code> labels to help attract more contributors. </p>
<h3 id="heading-step-5-adding-saved-replies">Step 5: Adding Saved replies</h3>
<p><a target="_blank" href="https://docs.github.com/en/get-started/writing-on-github/working-with-saved-replies/creating-a-saved-reply">Saved replies</a> is a feature on GitHub were you can create and save your own messages that you intend to use repeatedly in issues and pull requests.  </p>
<p>I decided to create the following replies:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screen-Shot-2022-10-31-at-7.59.09-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>I wanted replies to congratulate both first time and returning contributors because they took the time to make our repository better. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screen-Shot-2022-10-31-at-8.01.40-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>I also wanted to create a reply where I thanked the contributor for their contribution and requested changes to the pull request. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screen-Shot-2022-10-31-at-8.05.29-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The last reply I created was to let contributors know that their pull request was reviewed but was not going to be accepted. I saw that the main <a target="_blank" href="https://github.com/freeCodeCamp/freeCodeCamp">freeCodeCamp learn repository</a> used a similar reply so I wanted to include it in the Developer Quiz Site repository.  </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screen-Shot-2022-10-31-at-8.09.14-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-step-6-opening-up-github-discussions">Step 6: Opening up GitHub Discussions</h3>
<p>A few days before Hacktoberfest started, I wanted to open up another avenue for contributors to ask questions and propose new features. So I decided to open up <a target="_blank" href="https://docs.github.com/en/discussions">GitHub discussions</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screen-Shot-2022-10-31-at-8.14.52-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>When I created this post, we had a few people new to the repository feel welcomed to contribute and happy that there was a place to connect with me and other contributors. </p>
<p>Now that everything was in place, the countdown to Hacktoberfest was underway.</p>
<h2 id="heading-lessons-i-learned-during-hacktoberfest">Lessons I learned during Hacktoberfest</h2>
<p>Right from day 1, I was pretty busy reviewing pull requests and helping new contributors get started in open source. But the whole experience was very educational and rewarding. </p>
<p>Here are a few lessons that I learned during this time.</p>
<h3 id="heading-lead-with-patience-empathy-and-kindness">Lead with patience, empathy, and kindness</h3>
<p>We were all beginners once, and sometimes it is scary to learn something new. I made sure to lead with kindness and empathy because I remember what it was like to just start out in open source. </p>
<p>Every time a new question came in, I made sure to reply back and provide as much as assistance as I could to help them resolve the issue. This resulted in a welcoming and safe environment to learn.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screen-Shot-2022-11-01-at-6.25.48-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We also had times where some contributors wanted to add quiz questions but were nervous because English is not their first language. My job was to assure them that I was here to help and not pass judgement on spelling or grammar mistakes. </p>
<p>I believe that helped in the larger volume of quiz questions we ended up getting. </p>
<h3 id="heading-dont-get-worked-up-over-spam">Don't get worked up over spam</h3>
<p>One of the downsides to Hacktoberfest is the increased amount of spam pull requests for open source maintainers. While this is frustrating to deal with, I learned pretty quickly to just close the PR, label it as spam, and move on.</p>
<p>There was no point in arguing with them or getting upset because that is wasted energy. The majority of people did want to meaningfully contribute and that is where I chose to spend my energy.</p>
<h3 id="heading-how-to-gracefully-close-prs-that-will-not-be-accepted">How to gracefully close PR's that will not be accepted</h3>
<p>One of the surprising issues that came up were people wanting to take quiz questions and explanations from other quiz sites and add it to <a target="_blank" href="https://github.com/freeCodeCamp/Developer_Quiz_Site">freeCodeCamp's Developer Quiz Site</a>. The first couple of times this happened, I closed the pull request and let them know that this is plagiarism and we can't accept that. </p>
<p>Well, I received a response back from one contributor stating that they didn't realize and they wanted to know if they could try again. I assured them that they were free to create a new PR and I could help them with any spelling or grammar. </p>
<p>This led me to revise my response to let contributors know that they weren't in trouble and were free to contribute again in the future with their own questions.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screen-Shot-2022-11-01-at-6.42.40-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>This helped to maintain a healthy open source environment and most of those cases ended up being prolific contributors after they understood the rules. </p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>I am really glad that I participated as a maintainer in this year's Hacktoberfest. I learned a lot about communication, empathy, patience, and leadership.</p>
<p>I hope my post encourages you to want to get involved with open source either as a maintainer or contributor in the future. </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How I Developed My First Adventure Game ]]>
                </title>
                <description>
                    <![CDATA[ It's hard to tell exactly when my journey creating Occulto, a point and click adventure game, started. But I have a significant date in mind: 3 May 2018. Here's one thing that got the ball rolling: Luigi: Hello Andrea. Sorry to bother you. I would l... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-i-developed-my-first-game/</link>
                <guid isPermaLink="false">66d46011b6b7f664236cbe00</guid>
                
                    <category>
                        <![CDATA[ Art ]]>
                    </category>
                
                    <category>
                        <![CDATA[ C ]]>
                    </category>
                
                    <category>
                        <![CDATA[ #Game Design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Game Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ lessons learned ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                    <category>
                        <![CDATA[ unity ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Andrea Koutifaris ]]>
                </dc:creator>
                <pubDate>Wed, 09 Mar 2022 20:05:24 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/03/presentazione-new.min.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>It's hard to tell exactly when my journey creating Occulto, a point and click adventure game, started. But I have a significant date in mind:</p>
<p>3 May 2018.</p>
<p>Here's one thing that got the ball rolling:</p>
<blockquote>
<p>Luigi: Hello Andrea. Sorry to bother you. I would like to learn how to develop an app. Am I crazy?</p>
<p>Me (Andrea): Hmm... I don't have your number... who are you?</p>
</blockquote>
<p>Reading those two WhatsApp messages now makes me smile. But there are also two other pieces of interesting information:</p>
<p>First, that was May 2018. Now it is 2022... 3 years and some months later, we have published our very first game DEMO. So yes, it took us 3 years to release a demo.</p>
<p>But we are now producing at a steady pace, and in the first months of 2023 we will release the whole game.</p>
<p>That said, if you are planning to develop a game yourself, it won't necessarily take you 4 years…and I have some advice that hopefully will help!</p>
<p>Second, an app – everyone wants to make an app. Do we really need another app? What about a game instead? What I mean is: an adventure game is like a book, you install it, play it, enjoy and eventually uninstall it. It is not yet another app polluting your phone's memory.</p>
<p>Before I start, let me step back and explain what this article is about.</p>
<h2 id="heading-what-well-discuss-in-this-article">What We'll Discuss in This Article</h2>
<p>This article is about how I (Andrea) and Luigi developed <em>Occulto</em>, our first adventure game.</p>
<p>It will cover some technical aspects of the project, as well as how we managed creating and developing it. I'll discuss both psychological and practical parts of the journey.</p>
<p>I'll also provide a shallow comparison between using web technologies (like WebGL) for development vs Unity 2D.</p>
<p>This article consists of:</p>
<ul>
<li><p>A brief story about my passion for Adventure P&amp;C games, and how I ended up developing my own game.</p>
</li>
<li><p>A section about <em>Occulto</em>, the game I am developing</p>
</li>
<li><p>A tech section with a comparison between web technologies and Unity 2D</p>
</li>
<li><p>A section about what I learned through the process, along with some advice if you're creating your own game.</p>
</li>
</ul>
<h2 id="heading-how-i-got-into-adventure-games">How I got Into Adventure Games</h2>
<p>Many years ago, a good friend introduced me to <a target="_blank" href="https://amanita-design.net/games/machinarium.html">Machinarium</a>. Machinarium is one of the best adventure games I've ever played.</p>
<p>After I finished it, I felt the need to create my own adventure game. This feeling was not immediate, but grew stronger over time. Eventually it led me to find Luigi and be actually able to create my own indie game.</p>
<h3 id="heading-first-adventure-game-attempt">First adventure game attempt</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/10/newton-scene.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>In my first attempt at building a game, I contacted some friends and created a small group of people who were enthusiastic about creating an artistic P&amp;C game.</p>
<p>We managed to create a draft of the first scene (see the illustration above). The idea was to make an apple fall on Newton's head, who is resting under the tree.</p>
<p>I used the <a target="_blank" href="https://github.com/playn/playn">Playn Java framework</a> to write in Java and export to Android, iOS and web. At the time I was a Java developer. Playn is still an active project, it may be worth considering if you are looking for a Java 2D game framework.</p>
<p>This first attempt didn't last long. We had a dinner all together, and asked two friends to present us with a draft story of the game. And then I didn't get any feedback from the others and the project vanished into nothing.</p>
<h3 id="heading-second-attempt">Second attempt</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/10/cover-red-moony.min.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>In my second attempt I managed to create four scenes and some game-play among them. But the project failed because I wasn't ready to lead the project. You'll read about that soon.</p>
<p>Below you can see an image of one of the scenes of the game. It was intended to be a modern revisiting of Little Red Riding Hood were wolves were not bad :).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/10/room.min.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-third-and-final-adventure-game-attempt-occulto">Third and Final Adventure Game Attempt: Occulto</h2>
<p>Developing <em>Occulto</em> is my 3rd attempt at creating an adventure game – and hopefully this one is successful!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/10/village-editor.min.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Unity Editor: 1° Village</em></p>
<h3 id="heading-intro-to-the-game">Intro to the game</h3>
<p>It is a beautiful morning, and Eliot, a young mage apprentice, is going to the studio of his magister for a lesson about magical potions. Something is wrong from the first moment: why isn't the magister opening the door?</p>
<p>Inside the studio everything is a mess, and a note tells Eliot to go to the church in the village. What is going on? Where is the magister?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/10/studio.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>2° Magister studio</em></p>
<p>Will you help Eliot in his journey to find his magister and regain possession of the powerful forbidden book titled "The never written book" that an evil figure is trying to steal?</p>
<p>The demo consists of four scenes:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/10/monastery.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>3° Monastery</em></p>
<p>and one secret passage between the monastery and the private studio of a monk.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/10/secret-passage.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>4° Secret passage</em></p>
<p>Below you can see the last scene of the demo.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/10/hunckback-studio.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>5° Monk private studio</em></p>
<h2 id="heading-tech-i-used-to-build-my-adventure-game">Tech I Used to Build My Adventure Game</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/unity-vs-pixijs.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We developed <em>Occulto</em> in the beginning using <a target="_blank" href="https://pixijs.com/">Pixi.JS</a> and HTML. Then, later, I switched to Unity using the 2D features that are now included as default in the editor.</p>
<p>Since this article is quite long, I will not enter in the details of the code. But I will provide a description of the technologies we used and the process of creating the game.</p>
<p>I am planning to write a second article for the technical part.</p>
<p>We are a group of 3 people:</p>
<ul>
<li><p>Myself, Andrea, the developer and project/technical manager. I contribute to the story and game/riddle design as well. I am a software engineer.</p>
</li>
<li><p>Luigi, the wonderful artistic designer who designs and draws the scenes. He is also responsible for the game story and game-play. If you like the illustrations above, then you like Luigi's work :). He graduated in Mathematics.</p>
</li>
<li><p>Antonio is the music and sounds designer. He is a software engineer.</p>
</li>
</ul>
<p>Luigi draws the scenes using <a target="_blank" href="https://www.adobe.com/products/photoshop.html">Photoshop</a> and makes the animations using <a target="_blank" href="https://www.adobe.com/products/aftereffects.html">After Effects</a>. Then he exports everything into images (jpg and png) that I later use to assemble the scenes.</p>
<p>In addition Antonio provides me with the sounds and music for the scenes. We are using mp3 files at the moment, but we are planning to switch to <a target="_blank" href="https://www.fmod.com/">FMOD</a> in the future.</p>
<p>The game uses FHD (1920x1080) images, and runs also on low end mobile devices. If you want to run on a device with 1 GB of RAM, you need to reduce the amount of FHD images. If you load in memory more than 50/60 FHD images, the game may crash on devices with not enough memory.</p>
<p>In normal Unity memory management, the entire scene is loaded on memory, so you have to pay attention to what you add to the scene.</p>
<p>A simple and classic solution to reduce the memory imprint, is to use sprite sheets for the animations. Most of the time an animation will fit in a 2048x2048 sprite. I use <a target="_blank" href="https://www.codeandweb.com/texturepacker">Texture Packer</a> to create and import animation sprite sheets in Unity.</p>
<p>In addition I use <a target="_blank" href="https://imagemagick.org/index.php">ImageMagick</a> <a target="_blank" href="https://en.wikipedia.org/wiki/Command-line_interface">CLI</a> to trim images with an object inside. My input is a FHD transparent PNG with an object inside placed in the right position. Then I use:</p>
<pre><code class="lang-bash">magick mogrify -trim -verbose *.png &gt; trim.txt
</code></pre>
<p>to trim the image and get the precise position of the object.</p>
<p>Finally I add the trimmed image to the scene and place it using a script I made that maps the coordinates inside <em>trim.txt</em> file to the x,y values of the Unity scene.</p>
<p>By trimming and using sprite-sheets, I solved all memory problems. Also smaller images means lower time when loading a scene. In cheap mobile devices, loading a scene can require like 5 or 6 seconds (whereas in more powerful devices it takes less than a second).</p>
<p>Regarding fps and performance, Unity is good – so basically you don't have to do anything special. You just need to avoid bad design. And pay attention to <a target="_blank" href="https://en.wikipedia.org/wiki/Time_complexity">time complexity</a>. For example, avoid searching for an element on every tick of the game loop.</p>
<p>As I mentioned earlier, I am planning to write a tech article about how I developed the game using Unity 2D. If you are interested, follow me or follow us on one of our social accounts.</p>
<h3 id="heading-unity-vs-webgl">Unity vs WebGL</h3>
<p>Even if I used both technologies, I am not an expert (this is my first game). So below I will just list some of the pro and cons of both technologies.</p>
<h4 id="heading-pros-of-webgl">Pros of WebGL</h4>
<ul>
<li><p>Easy to port everywhere with <a target="_blank" href="https://capacitorjs.com/">Capacitor</a> or <a target="_blank" href="https://www.electronjs.org/">Electron</a>.</p>
</li>
<li><p>Programmers friendly: <a target="_blank" href="https://pixijs.com/">PixiJS</a> makes it very easy.</p>
</li>
<li><p>Almost the only working solution if you need a web responsive version.</p>
</li>
<li><p>Continuous integration and delivery to web is very easy, since the output is a bunch of files.</p>
</li>
<li><p>Web development is mature, and you have access to tons of libraries, utilities as well as a web packers, like <a target="_blank" href="https://webpack.js.org/">Webpack</a>.</p>
</li>
<li><p>Collaboration is very easy and mature with Git. There is something about collaboration in Unity, I didn't explore it. I don't know what happens if two people work on the same scene.</p>
</li>
</ul>
<h4 id="heading-cons-of-webgl">Cons of WebGL</h4>
<ul>
<li><p>Slightly lower performances compared to more native frameworks.</p>
</li>
<li><p>Subject to WebViews bugs (which you cannot solve).</p>
</li>
<li><p>It can be difficult for programmers who do not know web development.</p>
</li>
<li><p>WebViews doesn't seem to be ready to perfectly support WebGL. The game wasn't working well on my Neffos, and who knows on which devices it had issues. Maybe WebViews are not yet ready for gaming, but they are definitely ready for HTML and hybrids app.</p>
</li>
</ul>
<h4 id="heading-pros-of-unity">Pros of Unity</h4>
<ul>
<li><p>Graphical editor: it is easier to visualize/update the scene and fine tuning.</p>
</li>
<li><p>Easy and complete: it has almost everything you need.</p>
</li>
<li><p>Good performance: 60 fps even on low end devices at 1920 x 1080 resolution.</p>
</li>
<li><p>Cross platform, but the WebGL version does not work well on mobile phones.</p>
</li>
<li><p>A lot of indie games are made using Unity. If the Unity team introduces a bug, it will be found very soon.</p>
</li>
</ul>
<h4 id="heading-cons-of-unity">Cons of Unity</h4>
<ul>
<li><p>Graphical editor: you need a working updated Unity editor in each of the computers you are going to use. With Linux it's not that simple.</p>
</li>
<li><p><a target="_blank" href="https://store.unity.com/compare-plans">Closed licence</a> but it has a free tier if you earned up to $100K in the last 12 months.</p>
</li>
<li><p>At the moment the mobile web version is not officially supported.</p>
</li>
<li><p>Linux Unity editor is alpha (and I managed to make it work after many attempts).</p>
</li>
<li><p>Not a lot of helpful info about it: most of the posts I read to find help about a particular topic were low quality or were videos. That's far away from stack overflow quality. But the documentation is well done.</p>
</li>
</ul>
<p>Keep in mind that this section is not intended to be an exhaustive comparison between Unity 3D and WebGl frameworks. Depending on your target, one technology could be better than the other.</p>
<p>That said, even if I am a web developer, I must admit that Unity is great for developing a 2D games (and I guess 3D games too).</p>
<h2 id="heading-what-i-learned-while-building-occulto">What I learned While Building Occulto</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/1_zGuG4nFo8O4e0WMoNWVbMA.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-someone-needs-to-lead-the-project">Someone needs to lead the project</h3>
<p>This is my first insight: if it is you who propose a project to others (a game, an app or whatever), they will assume you will lead the project.</p>
<p>At the time I was thinking that I was just a programmer, and didn't act like a project leader. It won't work if someone doesn't actively follow every person in the project.</p>
<h3 id="heading-have-the-right-attitude">Have the right attitude</h3>
<p>It is important to have the right attitude towards people that are participating in the project. You also need to understand if they can be productive.</p>
<p>In this context, "productive" does not have the same meaning it has at work. Productive means "actually able to produce". At work it means how much you produce and how good is your output.</p>
<p>Before I go on, let me tell you a story:</p>
<p>Before embarking on <em>Occulto</em> game development, I decided to help a guy develop the interface for his board game. I did it because I thought the game he invented was a good game that had some brilliant parts to it.</p>
<p>In this case I was the developer, and he was leading the project (being the inventor of a game, doesn't unfortunately imply that you are also good as a project leader).</p>
<p>In the beginning everything was good, and I enjoyed developing the game. In addition I was learning React, which I used as the framework to build the game app. (It is a board game, not a classic one, so React was a good choice, and also it had a lot of pages, not just the game page).</p>
<p>Then things started to become weird: he started asking for deadlines, complaining about delays on the development, and asking for features which I thought weren't really useful in the first version of the game.</p>
<p>In the end it didn't work out and I couldn't work well with him, so I blocked all communication. Remember that I worked on his game for free, and I even solved a nasty bug that caused the back end side of the game to stop working.</p>
<p>So, why this story? To tell you that making a game with a bunch of friends is a very different job than what you do at work. Some advice:</p>
<ul>
<li><p><strong>Don't push people too hard</strong>: if you are making a game for fun, it must be fun. Motivate people and help them. They are working (as you are) for free on a project they believe in.</p>
</li>
<li><p><strong>Don't act like a boss</strong>: even if you direct and follow every step of the game, people should regard you more as a project manager/team leader than a boss.</p>
</li>
</ul>
<h3 id="heading-work-in-your-spare-time">Work in your spare time</h3>
<p>Being able to be "productive" applies also to you. Are you able to work in your spare time on the game? Can you provide a steady output, without long periods of time away from the project?</p>
<p>This is the first obstacle I encountered in my previous attempts. I wasn't able to provide a constant, timely output and people thought the project was falling apart.</p>
<p>In this case, as a programmer, it is important to integrate the output of your other team members (images, animations and sounds) as soon as possible. People will be more engaged if they see their work quickly integrated in the game. Also the sooner you integrate others' work, the sooner you will find and solve problems.</p>
<h3 id="heading-remove-as-many-obstacles-as-you-can">Remove as many obstacles as you can</h3>
<p>In order to work in your spare time, you have to reduce or remove all the obstacles. These can be physical (slow computer, too small a screen, ...) or psychological. The psychological ones are the most subtle. I will try to list some of them:</p>
<p><strong>Feeling guilty for not working</strong>: this is hard, and I think is one of the main reasons for quitting. You have to enjoy working on your project. So deadlines, pushing others to produce more, threatening (like "If you don't work enough you are out") do NOT work.</p>
<p>It is better to motivate people and help them understand what's blocking them (or you) to produce some output.</p>
<p><strong>Obstacles that delays the moment you can actually work</strong>: you may think something like "I'd like to finish that thing I started, I think I can complete it in 10 minutes." Then you think: "But the PC is slow and it will take forever to start... may be tomorrow, now I'll just serf on Instagram".</p>
<p>It is important that when you think you can work a bit on the game, you can actually do it without any delay or obstacle.</p>
<p><strong>Too tired to work on the game</strong>: indeed you must not overdo it. It is important to find a balance between how much you work and how much you rest. But it is also important to avoid long periods of not working on the game.</p>
<p>I noticed that small actions can help: for example for me it is enough to start the Unity Editor to increase the chances that I'll actually work on the game.</p>
<p><strong>Share your results with the others</strong>: even though non technical people may not fully understand what you are doing (and vice-versa), it is satisfying to explain that you solved a performance problem, or that you reduced the bundle size, for example.</p>
<p>In fact, in agile methodologies, telling what you did and what your are going to do is one of the main points.</p>
<p><strong>Persist</strong>. Not everything will be easy. You will have to persist. Even though you are probably making a game because of passion, it is still requires a lot of work and sometimes you have to persevere and overcome problems/blocks. You probably do that all the time at work, you can do it also for your game.</p>
<p><strong>Not every moment is a moment of pleasure</strong>. Imagine when I discovered that the demo, almost ready to be published, wasn't working on some mobile devices and I had to rewrite everything in Unity. I really had a bad weekend.</p>
<p>But then I manage to change my attitude, start with Unity, and regain pleasure in working on the game.</p>
<p>Fortunately Luigi, my partner in the game, understood it and accepted that we needed to delay the release date of the game demo. While it took a lot of time to write the demo (2 years, if you count from the first commit), it took me 3 months to rewrite it.</p>
<h3 id="heading-focus-on-developing-the-game">Focus on developing the game</h3>
<p>It is extremely important to focus on making the game, and not the framework for the game.</p>
<p>Being a programmer you will probably want to write more code than necessary and use your preferred language. Chose a framework based on your needs (cross platform? 2D or 3D? ...) and try to develop a simple level to understand if you made the right choices.</p>
<p>When you start, you won't necessarily have a clear view of the possible frameworks/technologies available to build a game – and there are a lot. In addition you will be biased towards some languages/features.</p>
<p>About that, I can tell you 2 mistakes I made:</p>
<p>I used PixiJS and HTML technologies at first. As opposite as you may think, I was able to go at 60 fps with FHD (1920x1080) resolution even in medium performance mobile devices.</p>
<p>This is because most of the work is done by WebGL. But at a certain point the game started flickering on my old mobile phone (Neffos X1 Max) when ported to a mobile app using Capacitor (webview). But it was working well on the browser and on the other phones I had. Even on my Motorola Moto G first generation (2013 low end device).</p>
<p>I should have tested earlier on mobile (not just with the browser). Also the game wasn't smooth on the my lower end device Moto G (still it was running near 30 fps).</p>
<p>I decided that I wanted my game to run smoothly even on low end devices, so I switched to Unity 2D. Unity is used by a lot of indie game developers, and C# is quite easy. I didn't try Unreal Engine, because I am too rusty on C++. Now it runs smoothly also on my Moto G (60 FPS).</p>
<p>The second thing that was almost a mistake is that I developed a library to find the shortest path on polygon areas with polygon holes. <a target="_blank" href="https://github.com/Kouty/shortest-path-polygon-area">Here</a> you can find the JS code (I have ported it to C#, but not yet release on GitHub).</p>
<p>I took me 3 attempts to get it working properly, and a lot of time. Fortunately by the time I started developing <em>Occulto</em>, the library was ready and working. Now I can just draw the walkable area and have the main character move inside it, avoiding obstacles (polygon holes).</p>
<p>The fact is that having an algorithm to move things inside a walk-able area is not strictly necessary, and it is better to focus on actually making the game. Other P&amp;C games do not use this feature, they just move characters along predefined paths.</p>
<p>So, before you embark on something that is not strictly necessary for the game, see if you can find something already implemented or if it is really worth it.</p>
<h3 id="heading-release-a-one-scene-version-of-the-game">Release a one scene version of the game</h3>
<p>After you've chosen the right framework, take a scene, and develop the entire game which will consist on one scene plus a menu and every UI component that is cross scene. It is important to learn everything you need and to find problems as soon as possible.</p>
<p>Also, submit the game for internal testing (not public) to the stores you are going to use. Yes, do everything that's necessary from developing to publishing (privately) the game.</p>
<p>When I published the game demo on iOS, one animation wasn't working. It was working on Android, Desktop, and even on iPhone with the developer build. So yes, you need to test everything as soon as possible, even the process of publishing.</p>
<p>I made the mistake to first develop the whole demo (four scenes, plus menu and some other screens) just to find out that WebGL technology was not the right choice for my game.</p>
<h2 id="heading-final-notes">Final Notes</h2>
<p>I hope you enjoyed reading this article and found some interesting advice. Maybe I will write another article when I have published the whole game, sharing other insights.</p>
<p>If you are curious about <a target="_blank" href="https://www.sirioartgames.com/"><em>Occulto</em></a> game, follow us on:</p>
<ul>
<li><p>Twitter: <a target="_blank" href="https://twitter.com/SirioArtGames">https://twitter.com/SirioArtGames</a></p>
</li>
<li><p>Instagram: <a target="_blank" href="https://www.instagram.com/sirioartgames/">https://www.instagram.com/sirioartgames</a></p>
</li>
<li><p>Our website: <a target="_blank" href="https://www.sirioartgames.com/">https://www.sirioartgames.com</a></p>
</li>
</ul>
<p>or <a target="_blank" href="http://onelink.to/mxsak4">try the demo</a>: <a target="_blank" href="http://onelink.to/occulto">http://onelink.to/occulto</a>!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Recover from Deployment Hell – What I Learned After My Discord Bot Crashed on a 1,000+ User Server ]]>
                </title>
                <description>
                    <![CDATA[ I built a Discord AI Chatbot in my last blog post and then, to challenge myself, proceeded to stress-test it on a Discord server with 1,000+ users. In the first hour, Deployment Hell struck and I had to take the bot down for maintenance. Another hour... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/recovering-from-deployment-hell-what-i-learned-from-deploying-my-discord-bot-to-a-1000-user-server/</link>
                <guid isPermaLink="false">66d46025264384a65d5a9594</guid>
                
                    <category>
                        <![CDATA[ #chatbots ]]>
                    </category>
                
                    <category>
                        <![CDATA[ deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ discord ]]>
                    </category>
                
                    <category>
                        <![CDATA[ lessons learned ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Life lessons ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Lynn Zheng ]]>
                </dc:creator>
                <pubDate>Fri, 04 Jun 2021 20:41:29 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/06/Untitled126_20210603134910.PNG" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>I built <a target="_blank" href="https://www.freecodecamp.org/news/discord-ai-chatbot/">a Discord AI Chatbot in my last blog post</a> and then, to challenge myself, proceeded to stress-test it on a Discord server with 1,000+ users.</p>
<p>In the first hour, Deployment Hell struck and I had to take the bot down for maintenance. Another hour passed and I managed to patch up my bot and send it back.</p>
<p>Now my bot is up and running and more resilient than ever. As for me, I survived and even thrived in Deployment Hell 🔥. In this deployment postmortem, I'm going to show you how.</p>
<p>I sent my AI chatbot into the server at 2 pm on June 2nd, and hype started gathering around it. The chat went on for a while and all was nice and smooth.</p>
<p>At 3:20 pm, everything started falling apart: My free-tier API key reached its hourly request limit, and I had no choice but to take down the bot and the server for maintenance.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/IMG_0676.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Never mind the typos in my message 😅 This incident caught me totally unprepared</em></p>
<p>Despite being struck by Deployment Hell in the first hour on the first day of my project debut, I knew I need to sit down, take a deep breath, and recover from this incident.</p>
<h1 id="heading-what-went-well-with-deployment">What Went Well with Deployment</h1>
<p>As a first step, I didn't forget to congratulate myself on what went well despite this mishap. Clearly, people were enthusiastic about chatting with my chatbot, to the extent that we went over rate limit.</p>
<p>Moreover, in the brief hour when I observed people interact with my bot in real time, I discovered several good design choices that I've consciously, unconsciously, or subconsciously made.</p>
<h2 id="heading-avoid-feature-creep-at-all-costs-during-development">Avoid Feature Creep At All Costs During Development</h2>
<p>I originally developed my code for a tutorial, so I kept my code as simple and readable as possible, without complicated features that won't serve my bot's main use case: chatting.</p>
<p>That said, I marked down <strong>TODOs and stretch goals</strong> in my code, hoping to get back to those if necessary. For example:</p>
<pre><code class="lang-python"> <span class="hljs-comment"># <span class="hljs-doctag">TODO:</span> cache chat history in DB and load</span>
 <span class="hljs-comment"># <span class="hljs-doctag">TODO:</span> after each user input and bot input,</span>
 <span class="hljs-comment"># append them to conversation history for the next query</span>
 ...
 <span class="hljs-comment"># <span class="hljs-doctag">FIXME:</span> better make this try-except block more fine-grained</span>
</code></pre>
<p>As I observed users interacting with the bot, I'm actually relieved that I didn't implement the <strong>memory cache feature</strong>. Several users were talking with the bot at once, each along their different conversation thread. If I were to keep track of the conversation history, I would have to create a unique log for each user, further complicating database operations.</p>
<h2 id="heading-abide-by-the-principle-of-least-privilege">Abide by the Principle of Least Privilege</h2>
<p>One thing I learned in my Computer Security class is the Principle of Least Privilege (PoLP) – granting an application the minimum amount of access it needs to do its job.</p>
<p>My chatbot only needs two low-level security permissions: <strong>View Channel</strong> for reading users' messages, and <strong>Send Text Messages</strong> for replying to users.</p>
<p>Of course I could have given it more fancy permissions like those shown below in the image, just in case it needs any. But that would have violated PoLP and who knows whether my malfunctioning bot will bring down anything else with it when it fails?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/Screen-Shot-2021-06-03-at-14.21.52-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Permission settings for Discord bots</em></p>
<h2 id="heading-other-observations-from-deploying-my-bot">Other Observations from Deploying My Bot</h2>
<p>Despite its ephemeral lifespan, my bot offered me an opportunity to conduct user research in the real world. This is a server with 1000+ users, not my cozy dev server where my friends and I hang out and take turns to politely exchange lines with the bot.</p>
<p>Here, I observed several interesting user behaviors:</p>
<ul>
<li><p>People tend to ask the bot <strong>open-ended questions</strong> instead of <strong>factual ones</strong>. Because I built my bot based off a video game character, when developing the AI model, I was keen on making sure the model learns the canon information about the character, like name, age, and role in the game. I was relieved when I saw that people are much more curious about the bot character's preference for ice cream flavor than their factual place of birth.</p>
</li>
<li><p>People use a lot of emoticons :), emojis 😃 and GIFs as they text. However, these will most likely be treated as <code>&lt;UNKNOWN&gt;</code> tokens in the AI model's tokenizer, which means I should <strong>sanitize</strong> user inputs.</p>
</li>
</ul>
<p>I was also very fortunate to receive direct feedback from friendly people on the server. One feature request that I got was to make the bot attach its response to a user's message thread, instead of just dumping its response in the channel.</p>
<p>Buzzing with excitement from people's enthusiasm and armed with insights from user research, I was ready to patch up my bot and send it back as soon as possible.</p>
<h1 id="heading-what-i-needed-to-fix">What I Needed to Fix</h1>
<p>As a good development habit, I kept my code well-organized and modularized, so switching from the production bot back to my development bot requires no more than copy-pasting the dev bot's API key.</p>
<p>Once I was running on my dev server, I sat down to identify the types of problems I needed to tackle.</p>
<h2 id="heading-fatal-crashes">Fatal Crashes</h2>
<p>The fatal bug that caused me to take down my bot was that I hit an hourly API rate limit. I took the obvious approach of keeping <strong>redundancy</strong> in my system: Keep an alternative API key, and once the primary one runs out, switch over to the alternative, and then switch back at the turn of the hour.</p>
<p>Workaround aside, I noted that this is a short-term solution. If I need to properly scale up my system, I should make an estimate of the number of requests per hour, as I'll discuss at the end of this section.</p>
<h2 id="heading-new-features-for-usability">New Features for Usability</h2>
<p>I decided on several new features that will make my bot more user-friendly. Some highlights are:</p>
<ul>
<li><p>As some server people suggested, I re-programmed the bot so that instead of dumping responses to different user messages into the channel, it directly responds to each user message in the message's thread.</p>
</li>
<li><p>I sanitized user inputs by removing Unicode emojis and Discord-specific <code>&lt;:some_hilarious_gif&gt;</code> tags. This will limit <code>&lt;UNKNOWN&gt;</code> tokens that my AI model will receive and help it generate better responses.</p>
</li>
<li><p>I implemented a magic command <code>$ignore [message]</code> that allow users to send a message to the channel without triggering a bot response. This feature comes from my observation that, whenever the bot says something funny or smart (or both!), users will remark on that by sending a text intended for their friends (and not the bot) to the channel. It'd be annoying to still receive a bot response on a remark intended for a friend. Hence, I hope that this magic command will address this user pain point.</p>
</li>
<li><p>I implemented magic commands for the server moderators to interface with my bot (stopping or rebooting) so that they can keep the bot under control without having to access my Repl.it server. This makes both my job and theirs easier.</p>
</li>
</ul>
<h2 id="heading-future-proof-logging">Future-proof Logging</h2>
<p>In my cozy dev server, there is little complexity, whereas on this 1000+ user server where 40% of users are online at any given moment, complexity explodes.</p>
<p>There are multiple channels besides the chat channel dedicated to my bot, multiple user roles and permission levels, multiple users typing at the same time, and so on.</p>
<p>While I certainly cannot prevent all possible failure scenarios, what I could do is to protect the important part of my code with a try-except block and log out all information that might reveal the cause of a failure. Since real-time system bugs are subtle and difficult to reproduce, logging will save me lots of headaches down the road.</p>
<pre><code class="lang-python"><span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
            print(e, <span class="hljs-string">'Offending channel'</span>, message.channel, 
            <span class="hljs-string">'Offending message'</span>, message.content, 
            <span class="hljs-string">'Offending bot response'</span>, bot_response, 
            sep=<span class="hljs-string">'\n'</span>, end=<span class="hljs-string">'\n\n'</span>)
</code></pre>
<h2 id="heading-scalability">Scalability</h2>
<p>Estimating under some system constraints is where basic statistics and heuristics come in. Hugging Face's model Inference API imposes two limits on the scalability of my system:</p>
<ol>
<li><p>A 10k tokens (characters) per hour rate limit, which is about 300 queries.</p>
</li>
<li><p>A 30k tokens per month quota for free-tier accounts, which is about 900 queries.</p>
</li>
</ol>
<blockquote>
<p>Wonder how I get the numbers? Fun fact: 1) <a target="_blank" href="https://capitalizemytitle.com/character-count/10000-characters/">10k characters is between 1430 and 2500 words</a>. We will take 2100 since Discord messages usually use simple, short words. 2) T<a target="_blank" href="https://crushhapp.com/texting-tidbits/the-average-text-message-length-is-around-7-words">he average length of a text message is 7 words</a>. 2100 / 7 = 300 messages</p>
</blockquote>
<p>After processing these numbers, the fact that I hit the per-hour rate limit during the first hour of my bot debut is quite a remarkable feat. People are clearly hyped about my witty chatbot. 🥳</p>
<p>Suppose the hype recedes and life goes on, consider now a hypothetical scenario where 20 users (2% of the 1000+ on the server) regularly chat with my bot, each for 25 lines, in the two hours following dinner. This produces a total of 500 queries in two hours (or 250 per hour), meaning that my bot is safe from the per-hour rate limit of 300.</p>
<p>However, in a month, 500 * 30 = 15,000 queries, 15 times more than my quota of 900. If my bot is indeed this popular, I would need to switch to a higher-tier subscription plan to ensure that it remains available.</p>
<h2 id="heading-from-tutorial-code-to-production-code">From Tutorial Code to Production Code</h2>
<p>Compared to my tutorial code which strives to be simple, readable, and educative, my production code is longer, more complicated, but also more robust.</p>
<h1 id="heading-what-makes-a-great-side-project">What Makes a Great Side Project</h1>
<p>Having emerged from Deployment Hell, like my bot, I'm more resilient than ever and have gained new insights about the principles and challenges in real-world software engineering.</p>
<p>As a final takeaway, I reflect on what makes my Discord AI chatbot this popular. (On June 3rd, a day when it's up 24 hours, it had already busted the monthly 30k quota on both my account and one I borrowed from a friend, totaling 2,000+ messages. 🤓)</p>
<p>I have completed and polished various side projects that received positive feedback, but none of them were as half popular as this one. In retrospect, it's not too hard to see why.</p>
<p>Among projects that I'm most proud of, I built <a target="_blank" href="https://github.com/RuolinZheng08/renpy-chess">a chess engine</a> and <a target="_blank" href="https://github.com/RuolinZheng08/renpy-rhythm">a rhythm game engine</a> for <a target="_blank" href="https://renpy.org/">the Ren'Py Visual Novel (VN) game development engine.</a> Both are rated 5-star on <a target="_blank" href="https://itch.io/">itch.io</a>, a popular platform for publishing indie games.</p>
<p>These projects, however, are open-source engines intended for developers to integrate into their VN games more than standalone playables that can entertain players for hours.</p>
<p>In comparison, my Discord AI chatbot manages to capture each of the following elements that distinguishes a <strong>great</strong> side project from a good one:</p>
<ul>
<li><p><strong>Audience:</strong> I'm fortunate to have this friendly server with 1000+ users who are open to experimenting with the bot and provide me with helpful feedback.</p>
</li>
<li><p><strong>Accessibility:</strong> For people to enjoy my chabot, there is nothing special they need to add to their routine - not even opening up a new web app - they just log into Discord as usual, and voilà, the bot is here to chat!</p>
</li>
<li><p><strong>Interactivity:</strong> Without interactive components, even the most visually-astonishing game will fail to retain players' attention. Nothing to worry about for my chatbot though: Like a loyal friend, it always has something to quip about whenever you need a good chat.</p>
</li>
</ul>
<p>If you'd like to learn more about my methodology for working on side projects, check out my previous blog post:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.freecodecamp.org/news/how-i-built-my-one-person-open-source-project/">https://www.freecodecamp.org/news/how-i-built-my-one-person-open-source-project/</a></div>
<p> </p>
<p>Also check out my chatbot tutorial!</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.freecodecamp.org/news/discord-ai-chatbot/">https://www.freecodecamp.org/news/discord-ai-chatbot/</a></div>
<p> </p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/UBwvFuTC1ZE" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<p>You can also try this out in JavaScript:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/XR6JFRLxe5A" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 5 Mistakes Beginner Web Developers Make – And How to Fix Them ]]>
                </title>
                <description>
                    <![CDATA[ By Dave Gray This list is made up of the most common mistakes I've witnessed during nearly a decade of teaching beginning web development students. My idea for writing this article is not to make fun of beginner mistakes or embarrass anyone who is be... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/common-mistakes-beginning-web-development-students-make/</link>
                <guid isPermaLink="false">66d45e043a8352b6c5a2aa13</guid>
                
                    <category>
                        <![CDATA[ beginners guide ]]>
                    </category>
                
                    <category>
                        <![CDATA[ coding ]]>
                    </category>
                
                    <category>
                        <![CDATA[ lessons learned ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ self-improvement  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 05 Apr 2021 16:48:42 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/04/varvara-grabova-NCSARCecw4U-unsplash-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Dave Gray</p>
<p>This list is made up of the most common mistakes I've witnessed during nearly a decade of teaching beginning web development students.</p>
<p>My idea for writing this article is not to make fun of beginner mistakes or embarrass anyone who is beginner.</p>
<p>Rather, my goal is to educate beginners and hopefully save them from some of these common mistakes.</p>
<h2 id="heading-we-were-all-beginners">We Were All Beginners</h2>
<p>If you aren't a beginner, you may think the mistakes listed below are obvious... but remember, obviousness is relative to experience.</p>
<p>Once upon a time, those of us with experience struggled with some of these mistakes, too.</p>
<p>If you are a beginner, I hope this list saves you some time and anxiety in the near future.</p>
<p>Let the countdown begin!</p>
<h2 id="heading-mistake-5-adding-spaces-in-file-names">Mistake #5: Adding Spaces in File Names</h2>
<p>You may save your HTML file with the name "my cool page.html", but those spaces between words are a mistake.</p>
<p>Web addresses (aka URLs) cannot have spaces.</p>
<p>If you load this file into your browser, you are going to see "my%20cool%20page.html" in the browser address bar. Spaces must be encoded because they are not allowed in URLs.</p>
<p>If you want to see separation between the words in your file names, use an underscore (my_cool_page.html) or a hyphen (my-cool-page.html).</p>
<p>As a beginner, you probably aren't too worried about search engine optimization (SEO), but <a target="_blank" href="https://developers.google.com/search/docs/advanced/guidelines/url-structure">Google has noted they prefer hyphens</a> in file names over underscores.</p>
<h2 id="heading-mistake-4-ignoring-case-sensitivity">Mistake #4: Ignoring cAsE sEnSiTiViTy</h2>
<p>If you are using Windows for your development environment, you might not notice a problem when you inconsistently use lowercase and capital letters. This is a mistake.</p>
<p>Let's say you created a CSS folder named "Css" and a file within it named "Main.css". But in your code, you link to it like this:</p>
<pre><code>&lt;link rel=<span class="hljs-string">"stylesheet"</span> href=<span class="hljs-string">"css/main.css"</span>&gt;
</code></pre><p>While you're working on your project, there is no problem.</p>
<p>But when you load your project to a web server...<strong>Boom!</strong> No CSS is applied.</p>
<p>Many web servers have some version of Linux or Unix running instead of Windows. You may have heard of the LAMP stack. Linux is the L in LAMP.</p>
<p>These systems are case sensitive.</p>
<p>Therefore, it is best to use lowercase file names and directory names all the time unless there is a specific naming convention that uses a capital letter. At that point, the file names will still always be consistent. And consistency is what will prevent this mistake.</p>
<h2 id="heading-mistake-3-not-understanding-file-paths">Mistake #3: Not Understanding File Paths</h2>
<p>Students that do not understand how to link files within different directories often dump all their files in the root directory in order to access them. This is a mistake that leads to an unorganized file tree.</p>
<p>Not long after you start learning HTML, you start learning how to link to other HTML and CSS files.</p>
<p>This is fairly straightforward when the files are in the same directory. Even in the example above, we just looked inside the CSS directory for the main.css file.</p>
<p>It starts to get more complicated when we need to go up a directory instead of (or before) going down into one.</p>
<p>In the example below, we are setting the background-image for a web page in our main.css file. The main.css file is in the CSS directory. We are linking to an image in the img directory.</p>
<pre><code>body {
     background-image: url(<span class="hljs-string">"../img/moon.png"</span>);
}
</code></pre><p>Both of these directories (aka folders) are in the root directory. Therefore, we need to go up and out of the CSS directory and then down into the img directory.</p>
<p>We go up one directory with two dots: ".."</p>
<p>From there, we go down into the img directory to link to the moon.png file.</p>
<p>If we needed to go up two directories, the file path would start like this: "../../"</p>
<p>Remember, one dot indicates the directory you are in. Two dots indicates the directory above where you currently are.</p>
<h2 id="heading-mistake-2-not-naming-your-default-page-index">Mistake #2: Not Naming Your Default Page Index</h2>
<p>Naming your default page something other than "index" is a mistake.</p>
<p>Web servers look for an index file.</p>
<p>When you're working with HTML, you should have an index.html file.</p>
<p>This file will load by default without showing the file name at the end of the URL.</p>
<p>That's why you can go to your favorite dot com or other web address and not see "/index.html" after their ".com". The index file loads by default.</p>
<p>Granted, your favorite website may use more than just HTML, but this concept carries over to other technologies like PHP (index.php), React (index.js), and more.</p>
<p>As you continue to learn, you will find some developers choose other file names when utilizing other technologies, but as a beginner, stick with index.</p>
<h2 id="heading-mistake-1-not-taking-a-break">Mistake #1: Not Taking A Break!</h2>
<p>I receive emails when students are frustrated.</p>
<p>They have poured over their project for hours and cannot find the error.</p>
<p>Often, the problem is a misspelled tag or variable, a missing semi-colon, or other small syntax error.</p>
<p><em>This happens to us all.</em></p>
<p>After staring at code for an extended time period, our vision blurs, our brains fizzle, and what would have been easy to see with fresh eyes becomes impossible.</p>
<p>Don't feel bad. Don't blame yourself. Just get up!</p>
<p>Take a walk. Get some coffee. Take a nap. Whatever snaps you out of the haziness and gives you fresh eyes and a clear head again.</p>
<p>Really, this mistake isn't just for beginners. It can happen to anyone.</p>
<p>I must remind myself to take breaks, too.</p>
<p>Come back to the code when you are refreshed and that error you couldn't find will often be obvious!</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>As you gain experience, you will quickly move past these common mistakes.</p>
<p>What was once difficult to understand will become clear.</p>
<p>If these common mistakes were obvious to you, congrats! You've already got some experience.</p>
<p>If you're just starting out, I hope this review of common beginner mistakes saves you both time and frustration in the near future.</p>
<p>I'll leave you with a video from my YouTube Channel that counts down the Top 10 Biggest Beginner Mistakes. Watch to see examples of the 5 mistakes I discussed in this article plus 5 additional common beginner mistakes:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/5xkztyg12FU" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How I Escaped Tutorial Purgatory – and How You Can, Too ]]>
                </title>
                <description>
                    <![CDATA[ By Daniel Chae Tutorial purgatory. We've all been there. The mindless scrolling, pausing, and playing. All the copying, and pasting of the coding snippets. It's a lukewarm place to be.  You're "learning" because you're making your way through structu... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/escape-tutorial-purgatory/</link>
                <guid isPermaLink="false">66d45e00d7a4e35e38434957</guid>
                
                    <category>
                        <![CDATA[ tutorial purgatory ]]>
                    </category>
                
                    <category>
                        <![CDATA[ learning to code ]]>
                    </category>
                
                    <category>
                        <![CDATA[ lessons learned ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Tutorial ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tutorial hell ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 23 Nov 2020 17:50:41 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/11/road-trip-with-raj-_cbKur5I60A-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Daniel Chae</p>
<p>Tutorial purgatory. We've all been there. The mindless scrolling, pausing, and playing. All the copying, and pasting of the coding snippets. It's a lukewarm place to be. </p>
<p>You're "learning" because you're making your way through structured content. But when you leave the tutorial, you can't code any of what you "learned". </p>
<p>The great thing is that you don't have to stay stuck in tutorial purgatory. I'm going to share with you my own experience about how I broke out of tutorial purgatory and how you can too. </p>
<p>Whatever method you decide to use, I'll share the key metrics for breaking out of the tutorial rut.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-259.png" alt="Image" width="600" height="400" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@dchuck?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit"&gt;Daniel Chekalov / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm<em>campaign=api-credit)</em></p>
<h2 id="heading-painful-realizations-about-my-learning-approach">Painful Realizations About My Learning Approach</h2>
<p>When I first started learning how to code I looked forward to learning anything and everything. </p>
<p>I'd Google "easy programming projects" and browse the first few search results. I kept my eyes peeled for tutorials because I thought I could avoid failure with the tutorial's help. I also believed that the more tutorials I completed, the more I would learn. </p>
<p>I couldn't have been more incorrect in my learning approach.</p>
<p>The unfortunate aspect was that I wasn't retaining the knowledge of what I was coding. After several months of "completing" tutorials, I soon came to grips with my lack of progress. I couldn't understand the code I was writing. </p>
<p>An example of this was when I completed a Flask tutorial. I thought I knew and understand Python from completing a tutorial. I decided to take w3 school's Python quiz and was confident I would pass. Unfortunately, I failed.</p>
<p>After I discovered I wasn't learning what I thought I was, I felt pretty hopeless. I thought tutorials were the key to learning. I thought about trying projects without tutorial help, but I was too scared to fail. I was burning with desire to become a great programmer, but I was out of ideas for how to do that.</p>
<h2 id="heading-how-i-broke-free-from-tutorial-purgatory">How I Broke Free from Tutorial Purgatory</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-260.png" alt="Image" width="600" height="400" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@pabloheimplatz?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit"&gt;Pablo Heimplatz / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm<em>campaign=api-credit)</em></p>
<p>I spent the next several months sulking, but not for long. There was a determination within me to find a way. </p>
<p>After months of not touching a single line of code I sat down and asked myself, "what is it that I want to work on? What type of programming is out there?"  </p>
<p>I sat and pondered answers to those two questions. I started researching different types of programming and various career paths. It was illuminating.</p>
<p>I found articles and forums on data science and analysis. I found helpful graphics that explained the difference between the front-end and back-end. I discovered how the front-end and back-end interact. I also found videos that explained what APIs were and how to view, receive, and write data from an API.</p>
<p>I would encourage you to ask the same questions:</p>
<blockquote>
<p>What is it that you want to work on? </p>
<p>What type of programming is out there?</p>
</blockquote>
<p>As you reflect on what it is you want to work on and explore, you'll begin to narrow down your learning path. </p>
<p>You'll feel less inclined to learn everything there is to know and more of what you are most interested in. You'll also feel less overwhelmed as you focus in on what type of programming interests you the most.</p>
<h2 id="heading-meetups-changed-my-life">Meetups Changed My Life</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-261.png" alt="Image" width="600" height="400" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@windows?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit"&gt;Windows / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm<em>campaign=api-credit)</em></p>
<p>Another thing I started doing was attending coding meetups. It's hard to imagine in-person meetups given that we're currently in a pandemic. But I remember my first coding meetup and how helpful it was.</p>
<p>Long story short, I had no idea what I was doing at the meetup. But I went with the intention to learn and open myself to different methods of programming. One of the facilitators ended up sitting me down and asked me why I was at the meetup. </p>
<p>After I told him I was there to learn more about programming, he helped me explore. He took me through different use cases for the Beautiful Soup and Selenium libraries. He ended up teaching me how to build a web scraper. After that meetup I realized data science and analysis interested me the most. </p>
<p>Throughout the next several months I had a renewed drive for programming. I had a specific vision and set of goals in mind. I began to complete small, simple projects. I built a web scraper that scraped financial data from the NASDAQ stock market. I also built a Java application that generated a random "workout of the day". </p>
<h2 id="heading-this-is-what-freedom-feels-like">This is What Freedom Feels Like</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-262.png" alt="Image" width="600" height="400" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@micahtindell?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit"&gt;Micah Tindell / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm<em>campaign=api-credit)</em></p>
<p>Over the course of the next year I could feel my confidence grow. As I completed small, simple projects my comprehension began to grow as well. I started to recognize more and more lines of code from other people's scripts on GitHub.  </p>
<p>Given that most of us are sheltering in place, I would recommend you don't go to an in-person coding meetup. That said, there are plenty of virtual coding meetups on <a target="_blank" href="https://www.meetup.com/">Meetup.com.</a> </p>
<p>I would also encourage you to check out the <a target="_blank" href="https://www.reddit.com/r/learnprogramming/">r/learnprogramming subreddit</a>. There are some snarky individuals on Reddit who may give you a hard time for asking questions. But there are also plenty of people who are more than willing to guide, inspire, and help you. If you allow them to, they'll help you become a better programmer.</p>
<h2 id="heading-your-keys-to-success-when-learning-to-code">Your Keys to Success When Learning to Code</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-263.png" alt="Image" width="600" height="400" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@mlightbody?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit"&gt;Malcolm Lightbody / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm<em>campaign=api-credit)</em></p>
<p>There are many ways to break out of tutorial purgatory. You don't have to do any of what I did. Whatever you choose to do, you should know there are a few key success metrics to guide you. </p>
<p>The most important metric is results. Are you able to complete projects without a tutorial guiding you every step of the way? Are you able to understand the problem and develop some type of approach? </p>
<p>Tutorials should help you so that you can go back and understand what you built with the tutorial's help. </p>
<p>The second metric is confidence. Do you feel like you're heading in the right direction? Do you feel like you're progressing? </p>
<p>Confidence can precede results, but it should never exist without results. Otherwise, you'll experience what I did while I was "completing" tutorials. You'll have, in essence, a false sense of confidence.</p>
<p>Tutorial purgatory is a miserable place to be. You don't know if you're heading in the right direction and learning to program can feel hopeless. </p>
<p>But take heart, you don't have to stay stuck in tutorial purgatory. Keep asking questions! Distill your vision so that you're not overwhelmed with having to learn everything. You're heading in the right direction if you're producing results and feeling confident. Time to break out of tutorial purgatory and you'll thank yourself later.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Things I Wish I Knew Before Working with Electron.js ]]>
                </title>
                <description>
                    <![CDATA[ By Alain Perkaz In this article, I'll share how you can avoid some of the mistakes I made when learning about Electron.js ?‍♂️. I hope it helps! Note: This wont be a coding tutorial, but rather a discussion about my personal takeaways. A couple of mo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/lessons-learned-from-electronjs/</link>
                <guid isPermaLink="false">66d45d9a37bd2215d1e24580</guid>
                
                    <category>
                        <![CDATA[ Electron ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ lessons learned ]]>
                    </category>
                
                    <category>
                        <![CDATA[ projects ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 28 May 2020 19:11:55 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9abd740569d1a4ca276a.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Alain Perkaz</p>
<p>In this article, I'll share how you can avoid some of the mistakes I made when learning about Electron.js ?‍♂️. I hope it helps!</p>
<p><strong>Note</strong>: This wont be a coding tutorial, but rather a discussion about my personal takeaways.</p>
<p>A couple of months back, I decided to focus more on building my side product, <a target="_blank" href="https://taggr.ai/"><em>taggr</em></a>. I was inspired to build it because of how many photos I have on my computer. </p>
<p>For those of us that keep a backup of their pictures, those collections often get so big and complex that they become a full-time job to manage. A mix of folders and sub-folders may contain instant messaging picture backups, hi-resolution pictures from your trip to Bali, your uncle's wedding, or last-year's bachelor party.</p>
<p>Always keeping such collections tidy is <strong>tedious</strong> (believe me, I have tried for years). It's also hard to discover the shots that you love the most, hidden deep within the folders. </p>
<p>So <a target="_blank" href="https://taggr.ai/"><em>taggr</em></a> is a desktop app that solves that problem. It lets users <strong>rediscover</strong> their memories while keeping their <strong>privacy</strong>.</p>
<p>I am building <em><a target="_blank" href="https://taggr.ai/">taggr</a></em> as a cross-platform desktop application. Here I'll share some of the things I've learned about cross-platform app development with <a target="_blank" href="https://www.electronjs.org/">Electron.js</a> that I wish I knew from the beginning. Let's get started!</p>
<h2 id="heading-background">Background</h2>
<p>Before presenting my takeaways on this ongoing journey with Electron, I would like to give a little more background about myself and the requirements of <a target="_blank" href="https://taggr.ai/"><em>taggr</em></a>.</p>
<p>Every developer comes from a different background, and so do the requirements of the applications they develop. </p>
<p>Contextualizing the choices I made for this project may help future developers select the right tools based on their needs and expertise (rather than what is hyped out there – GitHub ?, I am looking at you).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/train.gif" alt="Image" width="600" height="400" loading="lazy">
<em>JavaScript development in a nutshell. Source: [giphy](https://giphy.com/gifs/train-hype-FY2ew2Zii9VOE" rel="noopener).</em></p>
<p>As mentioned earlier, from the beginning I envisioned <a target="_blank" href="https://taggr.ai/"><em>taggr</em></a> as a cross-platform application. The app would perform all the required pre-processing and machine-learning computations client-side due to the focus on privacy. </p>
<p>As a one-person show, I wanted to be able to write my app once and ship it to different systems without losing my sanity.</p>
<p>From my side, I am a front end engineer in love with the web and JavaScript. I previously worked with Java and C#, but I enjoy the flexibility that the web provides and its vibrant ecosystem. </p>
<p>Having experienced first hand the pain of using tools like <a target="_blank" href="https://wiki.eclipse.org/Rich_Client_Platform">Eclipse RCP</a> to build client-side apps before, I knew I didn’t want to work with that tech again.</p>
<p>In short, my stack requirements for taggr boiled down to something like the following:</p>
<ul>
<li>It should provide <strong>cross-platform support,</strong> ideally at the framework level. ?</li>
<li>It should allow me to <strong>write the code once</strong>, and tweak for each platform if needed. ?️</li>
<li>It should enable <strong>access to machine-learning capabilities</strong>, regardless of the host environment, without specific runtimes to be installed. It should be painless to set up. ?</li>
<li>If feasible, it should <strong>use web technologies</strong>. It would be great to leverage my existing knowledge. ?</li>
</ul>
<p>As you can see, the requirements do not read as: <strong>I should use React with Redux, observables, and WebSockets</strong>. Those are lower-level implementation details, and they should be decided upon <em>when and if</em> the need arises. </p>
<p>Pick the right tool for the job rather than picking a stack from the beginning, disregarding the problems at hand.</p>
<p>So, after furious googling, I decided to give Electron a try. I hadn’t used that framework before, but I knew that many companies were using it successfully in products such as <a target="_blank" href="https://atom.io/">Atom</a>, <a target="_blank" href="https://code.visualstudio.com/">VS Code</a>, <a target="_blank" href="https://discord.com/">Discord</a>, <a target="_blank" href="https://signal.org/#signal">Signal</a>, <a target="_blank" href="https://slack.com/">Slack</a> and more.</p>
<p>Open-source and with out-of-the-box compatibility with both the the JS and Node ecosystems (Electron is build using Chromium and Node), Electron.js was an attractive tool for the work at hand. </p>
<p>I won't go too much into detail regarding the rest of the stack, as I repeatedly changed core parts (persistence and view layers) when needed, and it falls out of the scope of this article. </p>
<p>However, I would like to mention <a target="_blank" href="https://www.tensorflow.org/js">Tensorflow.js</a>, which enables running training and deploying ML models directly in the browser (with WebGL) and Node (with C bindings), without installing specific runtimes for ML in the host.</p>
<p>So back to Electron – thinking it was perfect, the fun began. ??</p>
<p>Enough talk about the background. Let’s dive into the takeaways.</p>
<h2 id="heading-1-start-small-and-slow">1. Start small (and slow) ?</h2>
<p>This is not a new concept, but it's worth bringing up periodically. Just because there are a ton of awesome <a target="_blank" href="https://github.com/sindresorhus/awesome-electron#boilerplates">starter projects</a> with Electron available, it doesn’t mean that you should pick one right away.</p>
<p><strong>Wait. What?</strong></p>
<blockquote>
<p>Slow is smooth, and smooth is fast. — Navy saying</p>
</blockquote>
<h3 id="heading-with-convenience-comes-complexity">With convenience comes complexity</h3>
<p>While those starters include many useful integrations (Webpack, Babel, Vue, React, Angular, Express, Jest, Redux), they also have their issues. </p>
<p>As an Electron newbie, I decided to go for a lean template that included the basics for ‘creating, publishing, and installing Electron apps’ without the extra bells and whistles. Not even Webpack in the beginning.</p>
<p>I recommend starting with something similar to <a target="_blank" href="https://www.electronforge.io/">electron-forge</a> to get up and running quickly, You can set up your dependency graph and structure on top to learn the ropes of Electron. </p>
<p>When the issues come (and they will), you will be better off if you build your custom starter project rather than picking <a target="_blank" href="https://github.com/electron-react-boilerplate/electron-react-boilerplate/blob/master/package.json">one</a> with +30 npm scripts and +180 dependencies to begin with.</p>
<p>That said, once you feel comfortable with Electron’s basis, feel free to step up the game with Webpack/React/Redux/TheNextHotFramework. I did it <strong>incrementally</strong> and when needed. Don’t add a realtime database to your todo app just because you read a cool article about it somewhere.</p>
<h2 id="heading-2-mindfully-structure-your-app">2. Mindfully structure your app ?‍♂️</h2>
<p>This one took a little longer to get right than I am happy to admit. ?</p>
<p>In the beginning, <strong>it may be tempting to mix up the UI and Backend code</strong> (file access, extended CPU operations), but things get complex quite fast. As my application grew in features, size, and complexity, maintaining one tangled UI+Backend codebase became more complicated and error-prone. Also, the coupling made it hard to test each part in isolation.</p>
<p>When building a desktop app that does more than an embedded webpage (DB access, file access, intensive CPU tasks…), I recommend <strong>slicing the app into modules</strong> and reducing the coupling. Unit testing becomes a breeze, and there is a clear path towards integration testing between the modules. For <a target="_blank" href="https://taggr.ai/"><em>taggr</em></a><em>,</em> I loosely followed the structure proposed <a target="_blank" href="https://blog.axosoft.com/electron-things-to-know/">here</a>.</p>
<p>On top of that, there is <strong>performance</strong>. The requirements and user expectations on this matter may vary wildly depending on the application that you are building. But blocking the main or render threads with expensive calls is never a good idea.</p>
<h2 id="heading-3-design-with-the-threading-model-in-mind">3. Design with the threading model in mind ?</h2>
<p>I won’t go too much into detail here – I'm just mainly doubling down on what is awesomely explained in the <a target="_blank" href="https://www.electronjs.org/docs/tutorial/performance">official docs</a>.</p>
<p>In the specific case of <a target="_blank" href="https://taggr.ai/"><em>taggr</em></a>, there are many long-running CPU, GPU, and IO intensive operations. When executing those operations in Electron’s main or renderer thread, the FPS count dips from 60, making the UI feel sluggish.</p>
<p>Electron offers several alternatives to <strong>offload those operations from the main and renderer threads</strong>, such as <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Worker">WebWorkers</a>, <a target="_blank" href="https://nodejs.org/api/worker_threads.html">Node Worker Threads</a>, or <a target="_blank" href="https://www.electronjs.org/docs/api/browser-window">BrowserWindow</a> instances. Each has its advantages and caveats, and the use case you face will determine which one is the best fit.</p>
<p>Regardless of which alternative you choose for offloading the operations out of the main and renderer threads (when needed), <strong>consider how the communication interface will be</strong>. It took me a while to come up with a interface I was satisfied with, as it heavily impacts how your application is structured and functions. I found helpfull to experiment with different approaches before picking one. </p>
<p>For example, if you think WebWorkers message passing interface may not be the easiest to debug around, give <a target="_blank" href="https://github.com/GoogleChromeLabs/comlink">comlink</a> a try.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/sponge.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Sponge Bob knows best. Source: [giphy](https://giphy.com/embed/jV4wbvtJxdjnMriYmY" rel="noopener)</em></p>
<h2 id="heading-4-test-test-and-test">4. Test ❌, test ❌, and test ✔️</h2>
<p>Old news, right? I wanted to add this as the last point, due to a couple of anecdotal ‘issues’ I recently faced. Strongly linked to the first and second points, building your custom starter project and making mistakes early on will save you precious debugging time further in the development.</p>
<p>If you followed my recommendations for splitting the app’s UI and Backend into modules with a clean interface between the two, setting up automated Unit and Integration tests should be easy. As the application matures, you may want to add support for <a target="_blank" href="https://www.electronjs.org/spectron">e2e testing</a> too.</p>
<h3 id="heading-gps-location-extraction">GPS location extraction ?️</h3>
<p>Two days ago, while implementing the GPS location extraction feature for <a target="_blank" href="https://taggr.ai/"><em>taggr</em></a><em>,</em> once the unit tests were green and the feature worked in development (with Webpack), I decided to try it in the production environment. </p>
<p>While the feature worked well in development, it failed miserably in production. The EXIF information from the pictures was read as binary and processed by a third-party library. While the binary information was correctly loaded in both environments (checked with <a target="_blank" href="https://www.lifewire.com/compare-two-text-files-linux-3861434">diff</a>), the third party library failed when parsing such data in the production build. Excuse me, ??</p>
<p><strong>Solution</strong>: I found out that the encoding settings in the development and production environments set by Webpack were not the same. This caused the binary data to be parsed as UTF-8 in development but not in production. The issue was fixed by setting up the proper encoding headers in the HTML files loaded by Electron.</p>
<h3 id="heading-funky-pictures">Funky pictures ?</h3>
<p>When manipulating and working with images, you may think that if a JPEG ‘just-works’ on your computer, it is a valid JPEG. <strong>Wrong</strong>.</p>
<p>While working with the Node image processing library <a target="_blank" href="https://sharp.pixelplumbing.com/"><em>sharp</em></a>, resizing some JPEG images crashed the app. After looking closely, the cause was incorrect JPEG images generated by <a target="_blank" href="https://github.com/lovell/sharp/issues/1578">Samsung firmware</a>. ?‍♂️</p>
<p><strong>Solution</strong>: setting up improved error boundaries in the app (ex. try-catch blocks), tweak the JPEG parsing module, and suspect of everything. ?️</p>
<h2 id="heading-summary">Summary</h2>
<p>The Node and JavaScripts ecosystems are blooming, with many powerful tools being created and shared every day.</p>
<p>The amount of options makes it hard to choose a clear path to start building your new awesome Electron app. Regardless of your frameworks of choice, I would recommend focusing on the following:</p>
<ol>
<li><strong>Start small</strong> and add complexity incrementally.</li>
<li><strong>Mindfully structure your app</strong>, keeping backend, and UI concerns modularized.</li>
<li><strong>Design with the threading model in mind</strong>, even when building small apps.</li>
<li><strong>Test and test again</strong>, to catch most of the errors early on and save headaches.</li>
</ol>
<p>Thanks for sticking around until the end! ?</p>
<p><a target="_blank" href="https://taggr.ai/"><em>taggr</em></a> is a cross-platform desktop application that enables users to <strong>rediscover</strong> their digital <strong>memories</strong> while keeping their <strong>privacy</strong>. Open-alpha is coming soon to Linux, Windows, and Mac OS. So keep an eye on <a target="_blank" href="https://twitter.com/TaggrOfficial">Twitter</a> and <a target="_blank" href="https://www.instagram.com/taggrofficial/">Instagram</a>, where I post development updates, upcoming features, and news.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What I've Learned in My First Year as a Software Engineer ]]>
                </title>
                <description>
                    <![CDATA[ By Lekha Surasani I just completed my first full year as a software engineer and it absolutely flew by.  Along the way, I learned a lot and I wanted to take some time to reflect on it and share what I've learned. Mentorship For a while, I downplayed ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/my-first-year-as-a-software-engineer/</link>
                <guid isPermaLink="false">66d4601af855545810e93499</guid>
                
                    <category>
                        <![CDATA[ Career ]]>
                    </category>
                
                    <category>
                        <![CDATA[ career advice ]]>
                    </category>
                
                    <category>
                        <![CDATA[ lessons learned ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Engineering ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 19 Sep 2019 15:00:00 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9ca052740569d1a4ca47f2.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Lekha Surasani</p>
<p>I just completed my first full year as a software engineer and it absolutely <em>flew</em> by. </p>
<p>Along the way, I learned a lot and I wanted to take some time to reflect on it and share what I've learned.</p>
<h2 id="heading-mentorship">Mentorship</h2>
<p>For a while, I downplayed the importance of mentorship in career growth. It takes a long time to find a good mentor, and quite frankly, I <em>still</em> haven't taken the time to find one. </p>
<p>Instead, I opted to learn as much as I could from senior engineers on my team. I was luckily comfortable enough with them to even ask career-related questions. Some examples of questions or advice I frequently asked for included:</p>
<ul>
<li>What are some good resources to learn x?</li>
<li>What are some things you look for in code reviews?</li>
<li>What are some things you wished you knew at the beginning of your career?</li>
<li>What was your salary at x years of experience?</li>
</ul>
<h2 id="heading-be-your-own-advocate">Be your own advocate</h2>
<p>In my experience, when you start a new job as a junior developer, your coworkers will underestimate you at every turn. I've gotten work assigned that's unfortunately simple, uninteresting, and too easy. </p>
<p>This was really frustrating because I felt myself growing bored at my job because I was doing things that weren't appropriately challenging. And, I'm guilty of letting this go on for too long (2-2.5 months). </p>
<p>It took a lot of internal pep talks, but I finally spoke up about it during a sprint planning meeting. </p>
<p>In hindsight, I didn't say much – I said I wanted more complex things to do. Then, I continued actively trying to take on tasks that I thought would be more appropriate, rather than trusting my coworkers to know what was best for me.</p>
<h2 id="heading-learn-how-to-ask-for-help">Learn how to ask for help</h2>
<p>I will admit, I'm still working on this one. I used to ask for help pretty readily early on, but as time passed, I got increasingly self-conscious about it. I was worried that I wasn't showing a better understanding of the code base over time. I was worried that my coworkers might think that I wasn't learning fast enough or that I just wasn't good at coding. </p>
<p>Getting over that insecurity and general imposter syndrome has been difficult. I can't say I've truly gotten over it, but I've taken some steps to mitigate the feeling, including:</p>
<ul>
<li>Writing down the question that I had or what I was having difficulty with. This showed me that over time, my questions were generally getting "smarter" and that I was asking about more complex things.</li>
<li>Teaching others what I found. If another engineer had a question that I could answer, I'd offer up my help even if I wasn't certain I was right. As you can imagine, my responses were littered with "I think", "Someone please correct me if I'm wrong", "maybe", "possibly", and "it could be"'s. Despite my fears about doing this, I tried my best to remember that it would be better for me in the long run. I could share what I had learned with others while getting feedback of my understanding from other engineers.</li>
<li>Talking about what I was feeling. Another junior engineer started at the same time I did, so I found that talking to her about my insecurities was really helpful. She was able to share how she was struggling as well, and it made me feel like I wasn't alone, or falling behind.</li>
</ul>
<p>Another reason I stopped asking for help was that often times, I got <em>too much</em> help. I would go to a senior engineer with what I thought was one simple question, and I would leave with all of the interesting parts of the task completed for me. I've been working on trying to ask more specific questions, and speaking up when I think I've got what I wanted, so the help I receive stops right there.</p>
<h2 id="heading-you-really-dont-have-to-be-an-expert-really">You really don't have to be an expert – really.</h2>
<p>"You don't have to be an expert". I heard this so many times while I was considering speaking at local meetups and conferences, and when I started trying to write technical articles. I didn't believe it for a long time – surely that's just what people are saying while they're already really good at said thing. </p>
<p>But one week, work had me diving into a <em>very specific</em> problem – we were upgrading <code>react-router</code> from v3 to v4. This upgrade required a lot of research as some key libraries were deprecated, and there were a ton of breaking changes. </p>
<p>I ended up learning so much about this one specific library. Over the course of many days, I had read so much documentation, github issues, and guides. I took all of the information I found and consolidated it since I hadn't found any one guide that would help explain what was going on in depth. </p>
<p>So, I <a target="_blank" href="https://www.freecodecamp.org/news/a-guide-to-upgrading-to-react-router-4/">wrote one myself</a>. It didn't get too much attention, of course. More importantly, I was relieved no one came after me with pitchforks. </p>
<p>Then, I thought about how many "intro to x" articles I read when I first started to learn a new language or framework. They were pretty basic articles, requiring a bit of background knowledge, but overall nothing too technically-controversial. </p>
<p>That's when I decided that React Hooks was going to be the topic of <a target="_blank" href="https://www.freecodecamp.org/news/lets-get-hooked-a-quick-introduction-to-react-hooks-9e8bc3fbaeac/">my next article</a>. I wasn't an expert on React Hooks by any measure. It had literally just come out and I'd only used it for some personal projects, but I'd written an article about it. So, really, you don't need to be an expert.</p>
<h2 id="heading-take-advantage-of-one-on-ones-with-your-manager">Take advantage of one-on-ones with your manager</h2>
<p>And if you don't do them currently, ask for them. I have mine once every two weeks. For me, I found these one-on-ones were a great opportunity for me to reflect on my work, ask questions about things I was confused about, and give general feedback about things that were working well and things that weren't. </p>
<p>Some specific questions and feedback included:</p>
<ul>
<li>How does this piece of the product work?</li>
<li>Do you see a consistent theme of things in my PRs that could be improved?</li>
<li>I'm enjoyed working on x, but I want to continue exploring other things, so do you think I could start getting work related to y?</li>
</ul>
<p>Because of these dialogues, I was able to get different kinds of tasks that I was more interested in, learn a lot more about the code base, and generally make parts of my job easier. </p>
<p>Each manager is different, though – so you may not be comfortable with asking the kinds of questions I've suggested, but at the very least, hopefully you can get some useful feedback on your work.</p>
<h2 id="heading-document">Document</h2>
<p>When you're early in your career especially, it's important to document what you're doing on a daily basis. It helps you see your growth, understand your work better, and overall, will help you reflect and understand what you've been working on. As a bonus, you'll be able to come up with points on your resume way easier! </p>
<p>I'm admittedly pretty bad at this. I jot things down in a notebook every week or so, and when I do, I only really take notes of the more complicated parts of our product. Ideally, you'd want to jot down what you accomplished that day and take notes on the code base and general "business logic" more often. </p>
<p>I don't think this is something that's talked/written about enough, but one of the people I follow on twitter, <a target="_blank" href="https://twitter.com/ceceliacreates">Cecelia Martinez</a>, recently asked her Twitter followers about tools they use to document things, so definitely <a target="_blank" href="https://twitter.com/ceceliacreates/status/1172187733961379840?s=20">check it out</a> if that's something you're interested in.</p>
<h2 id="heading-engage-in-the-community-at-large">Engage in the community at large</h2>
<p>The tech industry is problematic in many ways, but as a woman in tech, it helped me to follow others who had experienced similar things to me. <a target="_blank" href="https://twitter.com/ladyleet">Tracy Lee</a> (CEO of <a target="_blank" href="https://www.thisdot.co/labs">This Dot Labs</a>) has an excellent list of <a target="_blank" href="https://twitter.com/ladyleet/status/985018157994831872">women in tech to follow</a>. </p>
<p>I also joined my city's women who code chapter and I go to a few local meetups. As someone who gets very nervous meeting new people, I found it was a great way to network in a welcoming and friendly environment. </p>
<h2 id="heading-find-non-coding-hobbies">Find non-coding hobbies</h2>
<p>When I first started working, I felt a lot of pressure to keep up with the newest tech and to continue learning new things. But, I burnt out quickly because that was all I did. </p>
<p>I took a few steps back and decided to explore doing things I enjoy that weren't coding-related. I starting learning how to play the guitar and how to speak Hindi, I joined a book club, and I started going to the gym more. </p>
<p>All in all, I've learned a lot, and hopefully you've taken away some lessons from my experiences. I'm excited for what this next year holds for me!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How I Built and Shipped My First MVP ]]>
                </title>
                <description>
                    <![CDATA[ By JavaScript Joe On June 29th, I shared the MVP of mentored.dev on Twitter–my first "real" project that was bigger than anything I'd built before and something I was excited for other people to use.  https://twitter.com/jsjoeio/status/11449945802002... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-i-built-shipped-my-first-mvp/</link>
                <guid isPermaLink="false">66d45f63706b9fb1c166b983</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ lessons learned ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mvp ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 15 Jul 2019 13:15:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/07/Screen-Shot-2019-07-11-at-8.05.29-PM.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By JavaScript Joe</p>
<p>On June 29th, I shared the MVP of <a target="_blank" href="https://mentored.dev">mentored.dev</a> on Twitter–my first "real" project that was bigger than anything I'd built before and something I was excited for other people to use. </p>
<div class="embed-wrapper">
        <blockquote class="twitter-tweet">
          <a href="https://twitter.com/jsjoeio/status/1144994580200210432?s=20"></a>
        </blockquote>
        <script defer="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div>
<p>After sharing this, I received some bits of positive feedback, including a shout-out in the <a target="_blank" href="https://t.co/7sCziRMC9f?amp=1">npm weekly newsletter</a>. </p>
<p>I thought I'd share the story behind the whole process.</p>
<h2 id="heading-origin-of-the-idea">Origin of the Idea</h2>
<p>I can't remember when I first had the idea but a while back when I was introduced to <a target="_blank" href="https://www.twilio.com/quest">TwilioQuest</a>, I thought to myself, </p>
<blockquote>
<p>Wouldn't it be cool to build a "gamified" learning platform that taught you how to code?</p>
</blockquote>
<p>Like many other people, I have these ideas at random times throughout my life. I keep a list of these ideas in a <a target="_blank" href="https://trello.com/en-US">Trello</a> board called "IDEAS". Looking here, I can see I notated this on January 21st, 2019. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/07/trello-card1.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Trello board with original idea from Jan. 21st</em></p>
<p>I knew a few things:</p>
<ul>
<li>I wanted it to be interactive</li>
<li>I wanted it to feel like a game</li>
<li>I wanted it to have quick exercises</li>
</ul>
<hr>
<h2 id="heading-where-to-start">Where to Start?</h2>
<p>Around that same time, I was wrapping up a freelance project (porting a Jekyll theme to a Gatsby site) so I didn't feel like I was ready to start it just yet. Then, I had a conversation with <a target="_blank" href="https://twitter.com/signalnerve">@signalnerve</a> on Twitter that sparked my motivation:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/07/Screen-Shot-2019-07-09-at-6.20.11-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Screenshot of Twitter conversation that motivated me to start.</em></p>
<blockquote>
<p>Build a small app–a real MVP–validate your idea and then decide if you should keep building. </p>
</blockquote>
<p>So I thought, "What the heck, why not start it?"</p>
<hr>
<h2 id="heading-march-2019">March 2019</h2>
<p>I used a Gatsby/TypeScript starter to kickstart the first and pushed my <a target="_blank" href="https://github.com/jsjoeio/mentored.dev/commit/0e38821f30d1f6f1bca804315fe24ccd5d5baf05">first commit</a>. Originally, I named the repo "Life of Code" because that's what came to mind but later I renamed it after buying the mentored.dev domain. </p>
<h4 id="heading-initial-wireframes">Initial Wireframes</h4>
<p>After creating the repo, I sketched up some elementary wireframes in <a target="_blank" href="https://figma.com">Figma</a></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/07/figma.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Initial Wireframes in Figma</em></p>
<p>Once I had all this, I felt over the initial "where-do-I-begin-paralysis" and knew I needed to keep the momentum going. </p>
<h4 id="heading-taking-input">Taking Input</h4>
<p>One of the first things I tried was asking for user input and showing that in a message. This would be useful for the dialog between the narrator and the user. </p>
<div class="embed-wrapper">
        <blockquote class="twitter-tweet">
          <a href="https://twitter.com/jsjoeio/status/1103860530605780998?s=20"></a>
        </blockquote>
        <script defer="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div>
<h3 id="heading-basic-dialog-working">Basic Dialog Working</h3>
<p>Even though it didn't look pretty, the logic for the dialog was working! This felt like a good milestone because most of the hard stuff was done. </p>
<div class="embed-wrapper">
        <blockquote class="twitter-tweet">
          <a href="https://twitter.com/jsjoeio/status/1106779197614088192?s=20"></a>
        </blockquote>
        <script defer="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div>
<h3 id="heading-narrator-character-talking">Narrator Character Talking</h3>
<p>I struggled a lot figuring out the best way to get the narrator talking but after finding <code>[react-keyframes](https://github.com/zeit/react-keyframes)</code>, I was able to figure out a solution. This was huge because previously I hadn't done much with animation.</p>
<div class="embed-wrapper">
        <blockquote class="twitter-tweet">
          <a href="https://twitter.com/jsjoeio/status/1107812366891180032?s=20"></a>
        </blockquote>
        <script defer="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div>
<h3 id="heading-getting-feedback-on-dialog">Getting Feedback on Dialog</h3>
<p>As stated earlier, I think it's important to get input from others. I don't know if Twitter is the best place to do it but fortunately for me, the people who responded to my request for feedback were kind.</p>
<div class="embed-wrapper">
        <blockquote class="twitter-tweet">
          <a href="https://twitter.com/jsjoeio/status/1108190126876680193?s=20"></a>
        </blockquote>
        <script defer="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div>
<h3 id="heading-migrating-to-typescript">Migrating to TypeScript</h3>
<p>I used a Gatsby-TypeScript starter for this project because I had been meaning to learn TS. However, up until this point, I wasn't actually using TS. The files just had .ts or .tsx endings.</p>
<p>Before the 30th, I had mentioned wanting to learn TS and <a target="_blank" href="https://twitter.com/TejasKumar_">@TejasKumar_</a> offered to teach me by migrating the mentored.dev codebase over to TS on a Google Hangouts livestream. This was one of the coolest moments of this project. And I learned a ton. </p>
<div class="embed-wrapper">
        <blockquote class="twitter-tweet">
          <a href="https://twitter.com/jsjoeio/status/1112088320182370304?s=20"></a>
        </blockquote>
        <script defer="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div>
<hr>
<h2 id="heading-april-2019">April 2019</h2>
<h3 id="heading-adding-a-profile-card-component">Adding a "Profile Card" Component</h3>
<p>Next up after finishing the dialog part of the project, I decided to focus on the Dashboard - or the page after you logged in. I created a simple "Profile Card" that will eventually show your experience, any code-cash you have, etc.</p>
<div class="embed-wrapper">
        <blockquote class="twitter-tweet">
          <a href="https://twitter.com/jsjoeio/status/1113644342172774400?s=20"></a>
        </blockquote>
        <script defer="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div>
<h3 id="heading-designing-the-dashboard">Designing the Dashboard</h3>
<p>In hindsight, I may have gotten ahead of myself here because I designed way more than I could implement in the MVP but at least it gave me an idea for the future. I first added it as hard-coded components but later commented out to maintain a healthy UX.</p>
<div class="embed-wrapper">
        <blockquote class="twitter-tweet">
          <a href="https://twitter.com/jsjoeio/status/1114009915545141249?s=20"></a>
        </blockquote>
        <script defer="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div>
<h3 id="heading-designing-the-campus-map">Designing the Campus Map</h3>
<p>This took way longer than I thought. I wanted it to feel like a university campus but drew heavily from <a target="_blank" href="https://bulbapedia.bulbagarden.net/wiki/Pallet_Town">Pallet Town</a> in Pokemon. The completed version has more but at least I had something I could add to the Dashboard. I designed all of this in Figma and exported it as SVG. Working with SVGs in React has proven to be a delightful experience. </p>
<div class="embed-wrapper">
        <blockquote class="twitter-tweet">
          <a href="https://twitter.com/jsjoeio/status/1114635991191396352?s=20"></a>
        </blockquote>
        <script defer="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div>
<h3 id="heading-adding-gameplay-music">Adding Gameplay Music</h3>
<p>I never realized how hard it is to create or find music for a game. I ended up finding this amazing sound artist named <a target="_blank" href="https://www.soundimage.org">Eric Matyas</a> who makes music and sounds royalty-free. I wanted the audio to start automatically (because that's how most games do it) but unfortunately that is <a target="_blank" href="https://a11yproject.com/posts/never-use-auto-play/">not accessible</a> so it does not auto-play. </p>
<p>However, if you turn it on at the start menu or when you're playing the game, it adds a nice touch.</p>
<div class="embed-wrapper">
        <blockquote class="twitter-tweet">
          <a href="https://twitter.com/jsjoeio/status/1115436705346019328?s=20"></a>
        </blockquote>
        <script defer="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div>
<h3 id="heading-changing-maps">Changing Maps</h3>
<p>This has to be my favorite feature I added–being able to change the map. At first, I had no idea how I was going to do this, then I thought, "why not just swap the map with another map?"</p>
<p>So that's exactly what I did and it worked! </p>
<p>I extracted the parts of the map that were clickable (like the buildings) and made it so they open up different maps. I don't know how well my solution will scale but hey, it's working right now and that's what matters. </p>
<div class="embed-wrapper">
        <blockquote class="twitter-tweet">
          <a href="https://twitter.com/jsjoeio/status/1119834245013196801?s=20"></a>
        </blockquote>
        <script defer="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div>
<h3 id="heading-courses-page">Courses Page</h3>
<p>One of the other challenges I faced was figuring out where and how to show the courses (i.e. the dialog with the narrator).</p>
<p>Same thing–I struggled with this for a bit then decided, "Let's show it in an Overlay component!"</p>
<p>That ended up working out well. Again, I don't know if that will scale well but it works for now.</p>
<div class="embed-wrapper">
        <blockquote class="twitter-tweet">
          <a href="https://twitter.com/jsjoeio/status/1123063970468786176?s=20"></a>
        </blockquote>
        <script defer="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div>
<hr>
<h2 id="heading-may-2019">May 2019</h2>
<p>In May, I took a little bit of a break. I was getting married so I wanted to focus on prepping for that rather than my game. I still had ideas for things here and there but I didn't put in nearly as much time as March or April. </p>
<p>Even though it's difficult for me to take breaks and step away, I think it's healthy to go outside, change what you're doing, mediate, etc. As my mother always says, </p>
<blockquote>
<p>Everything in moderation. </p>
</blockquote>
<hr>
<h2 id="heading-june-2019">June 2019</h2>
<p>Looking at the Dashboard I created, there was still so much left to do. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/07/Dashboard-v1.1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>I felt overwhelmed.</p>
<p>"How am I going to finish all this?"</p>
<h3 id="heading-a-realization-at-the-phoenix-reactjs-meetup">A Realization at the Phoenix ReactJS Meetup</h3>
<p>I hadn't been to the <a target="_blank" href="https://www.meetup.com/Phoenix-ReactJS/">Phoenix ReactJS Meetup</a> in a while. My two coworkers and I decided to go hear the lightning talks.</p>
<p>Before the talks, we were crowded around a table, chatting about our side projects. I said I wanted to finish the MVP for mentored.dev by the end of the year.</p>
<p>"How much more do you have to finish?" </p>
<p>"A decent amount. Everything on the Dashboard page is hard-coded at the moment."</p>
<p>"Drop all that. Finish the core features and ship it."</p>
<p>Those were the wise words from my coworkers. That's when I realized they were right. I decided to cut scope and implement two last features–the streak tracker and the lesson progress.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/07/Screen-Shot-2019-07-10-at-8.06.01-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Screenshot of the streak tracker</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/07/Screen-Shot-2019-07-10-at-8.06.13-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Screenshot of lesson progress</em></p>
<p>The streak tracker logic was buggy when I first implemented it and didn't work at all. I wasn't sure if I should only increment the streak after 24-48 hours, or just do it by the day, or what. It <a target="_blank" href="https://github.com/jsjoeio/mentored.dev/issues/93">seemed a lot more complicated</a> than it should have been.</p>
<p>I still don't know if I'm happy with the implementation. But again, it's out the door and the basic functionality works. </p>
<p>The lesson progress (completed - 1/3) is also rudimentary at best. Again, my focus was to get it out the door. I'll style it in the future. </p>
<h3 id="heading-ship-it">Ship It</h3>
<p>June 29th. The big day.</p>
<div class="embed-wrapper">
        <blockquote class="twitter-tweet">
          <a href="https://twitter.com/jsjoeio/status/1144994580200210432?s=20"></a>
        </blockquote>
        <script defer="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div>
<p>As I say in the tweet thread, </p>
<blockquote>
<p>...It's nowhere near complete but I think this is a good stopping point to share the MVP.</p>
</blockquote>
<p>A while back, I read <em><a target="_blank" href="http://theleanstartup.com/">Lean Startup</a></em> by Eric Ries. One thing that always stuck with me was something he said along the lines of, "You should be embarrassed putting your product out there. That's when you know it's an MVP."</p>
<p>And that's how I felt! So much left to do. It's hard to even consider it a "game"–most real gamers probably wouldn't.</p>
<p>But that's the point–it helped lift a burden off my shoulders and step back to hear what people think.</p>
<p>Most people I've talked to think it's a good start and a neat concept. They're excited to see where it goes.</p>
<hr>
<h2 id="heading-what-i-think-worked">What I Think Worked</h2>
<p>Reflecting on what helped me launch this MVP, a few things come to mind. </p>
<h3 id="heading-accountability-friends-amp-twitter-community">Accountability - Friends &amp; Twitter Community</h3>
<p>As we all know, it's very easy to silo yourself and work alone. This might work for some people and that's fine. But in my case, I think sharing this project with my coworkers held me more accountable than if I hadn't told anyone. Each week on Monday mornings, one of them would ask, "Hey Joe. Did you work on your game?"</p>
<p>Their interest and support meant a lot to me. They wanted to see it succeed as much as I did. That kept me going.</p>
<p>The other part that kept me accountable was sharing it with people on Twitter. Sometimes people would comment and other times they wouldn't. Either way, people were following along. A few would DM me asking how it was coming along.</p>
<p>By sharing it in public, I felt a bit of pressure (in a good way) to finish it.</p>
<h3 id="heading-using-github-projects-issues-and-milestones">Using GitHub Projects, Issues, and Milestones</h3>
<p>I treated this project like we treat client/company applications at work. I didn't use sprints per se but I did keep a list of tasks in a <a target="_blank" href="https://github.com/jsjoeio/mentored.dev/projects/3">GitHub Project board</a> and then select a few and create a milestone. This made the work feel more achievable and less overwhelming. </p>
<p>I set up a staging environment at <a target="_blank" href="https://staging.mentored.dev">https://staging.mentored.dev</a> (thanks to <a target="_blank" href="https://www.netlify.com/">Netlify</a>, this was straightforward). Then, each issue I finished, I submitted a PR to merge into staging. I reviewed and merged myself (yes, a bit silly, but good practice). </p>
<p>Once a <a target="_blank" href="https://github.com/jsjoeio/mentored.dev/milestones?state=closed">milestone was complete</a>, I merged staging into master and created a new release. This process set me up for success. I kept milestones small (something I could finish in 1-3 weeks). </p>
<p>Having some type of project management in place for your side project I believe will help you reach the finish line sooner. </p>
<h3 id="heading-cutting-scope">Cutting Scope</h3>
<p>I wouldn't have finished this MVP if I hadn't cut a lot of features. For instance, I really wanted to create a repository called "mentored-dev" after the user logged in and store the lesson progress there. But that was going to take more time than I anticipated so I cut it. </p>
<p>Instead, I store the progress in localstorage. Yes, it's short-term but again, I had to cut scope to ship. If I hadn't, I wouldn't have finished this phase of the project.</p>
<hr>
<h2 id="heading-closing-thoughts">Closing Thoughts</h2>
<p>Overall, I feel thankful for all the support. I'm proud of the small project I built and the feedback I have received, so thank you. As for the next steps, I've already created the <a target="_blank" href="https://github.com/jsjoeio/mentored.dev/milestone/6">next milestone</a>. The main thing is to finish all the lessons for the basics of the command line and then share that to see what people think.</p>
<p>As far as actual features–I wouldn't promise anything but I'd love to add experience points (XP) which you accumulate based on your score in the lessons or how many times you take each lesson, how often you login, etc.</p>
<p>It would also be nice to give XP for doing things outside the game (i.e. writing a blog post, tweeting something you learned, contributing to open source, helping someone, etc). We'll see what happens though.</p>
<p>Thank you for listening to the journey. </p>
<p>###</p>
<p>If you enjoyed this article or found it interesting, please share it with others or let me know on <a target="_blank" href="https://twitter.com/jsjoeio">Twitter</a>.</p>
<p>To stay up to date on mentored.dev or other things I'm working on, I have a newsletter you can <a target="_blank" href="https://github.com/jsjoeio/mentored.dev/milestone/6">sign up for here</a>.</p>
<p>Happy coding! </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How I reverse-engineered the  Hemingway Editor - a popular writing app - and built my own from a beach in Thailand ]]>
                </title>
                <description>
                    <![CDATA[ By Sam Williams I’ve been using the Hemingway App to try to improve my posts. At the same time I’ve been trying to find ideas for small projects. I came up with the idea of integrating a Hemingway style editor into a markdown editor. So I needed to f... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/https-medium-com-samwcoding-deconstructing-the-hemingway-app-8098e22d878d/</link>
                <guid isPermaLink="false">66d460d98812486a37369d48</guid>
                
                    <category>
                        <![CDATA[ english ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ lessons learned ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ writing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 03 Jul 2019 04:30:00 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9ca1be740569d1a4ca5067.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Sam Williams</p>
<p>I’ve been using the Hemingway App to try to improve my posts. At the same time I’ve been trying to find ideas for small projects. I came up with the idea of integrating a Hemingway style editor into a markdown editor. So I needed to find out how Hemingway worked!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/07/Hemingway_Editor.png" alt="Image" width="600" height="400" loading="lazy">
<em>A screenshot of the Hemingway Editor</em></p>
<h3 id="heading-getting-the-logic">Getting the Logic</h3>
<p>I had no idea how the app worked when I first started. It could have sent the text to a server to calculate the complexity of the writing, but I expected it to be calculated client side.</p>
<p>Opening developer tools in Chrome ( Control + Shift + I or F12 on Windows/Linux, Command + Option + I on Mac) and navigating to <em>Sources</em> provided the answers<em>.</em> There, I found the file I was looking for: <strong>hemingway3-web.js.</strong></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/5j4RVt-ESeQ5r1KyFgUI4bQ9lzJeEY0FQfpE" alt="Image" width="800" height="455" loading="lazy">
<em>Minified file on the top, Formatted file on the bottom. What a difference it makes!</em></p>
<p>This code is in a minified form, which is a pain to read and understand. To solve this, I copied the file into VS Code and formatted the document (<em>Control</em>+ <em>Shift</em> + <em>I</em> for VS Code). This changes a 3-line file into a 4859-line file with everything formatted nicely.</p>
<h3 id="heading-exploring-the-code">Exploring the Code</h3>
<p>I started to look through the file for anything that I could make sense of. The start of the file contained immediately invoked function expressions. I had little idea of what was happening.</p>
<pre><code class="lang-js">!<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">e</span>) </span>{
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">t</span>(<span class="hljs-params">r</span>) </span>{
      <span class="hljs-keyword">if</span> (n[r])
          <span class="hljs-keyword">return</span> n[r].exports;
      <span class="hljs-keyword">var</span> o = n[r] = {
          <span class="hljs-attr">exports</span>: {},
          <span class="hljs-attr">id</span>: r,
          <span class="hljs-attr">loaded</span>: !<span class="hljs-number">1</span>
      };
...
</code></pre>
<p>This continued for about 200 lines before I decided that I was probably reading the code to make the page run (React?). I started skimming through the rest of the code until I found something I could understand. (I missed quite a lot that I would later find through finding function calls and looking at the function definition).</p>
<p>The first bit of code I understood was all the way at line 3496!</p>
<pre><code>getTokens: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">e</span>) </span>{
  <span class="hljs-keyword">var</span> t = <span class="hljs-built_in">this</span>.getAdverbs(e), 
    n = <span class="hljs-built_in">this</span>.getQualifiers(e),
    r = <span class="hljs-built_in">this</span>.getPassiveVoices(e), 
    o = <span class="hljs-built_in">this</span>.getComplexWords(e);
  <span class="hljs-keyword">return</span> [].concat(t, n, r, o).sort(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">e, t</span>) </span>{
    <span class="hljs-keyword">return</span> e.startIndex - t.startIndex
  })
}
</code></pre><p>And amazingly, all these functions were defined right below. Now I knew how the app defined adverbs, qualifiers, passive voice, and complex words. Some of them are very simple. The app checks each word against lists of qualifiers, complex words, and passive voice phrases. <code>this.getAdverbs</code> filters words based on whether they end in ‘ly’ and then checks whether it’s in the list of non-adverb words ending in ‘ly’.</p>
<p>The next bit of useful code was the implementation of highlighting words or sentences. In this code there is a line:</p>
<pre><code class="lang-js">e.highlight.hardSentences += h
</code></pre>
<p>‘hardSentences’ was something I could understand, something with meaning. I then searched the file for <code>hardSentences</code> and got 13 matches. This lead to a line that calculated the readability stats:</p>
<pre><code class="lang-js">n.stats.readability === i.default.readability.hard &amp;&amp; (e.hardSentences += <span class="hljs-number">1</span>),
n.stats.readability === i.default.readability.veryHard &amp;&amp; (e.veryHardSentences += <span class="hljs-number">1</span>)
</code></pre>
<p>Now I knew that there was a <code>readability</code> parameter in both <code>stats</code> and <code>i.default</code>. Searching the file, I got 40 matches. One of those matches was a <code>getReadabilityStyle</code> function, where they grade your writing.</p>
<p>There are three levels: normal, hard and very hard.</p>
<pre><code class="lang-js">t = e.words;
n = e.readingLevel;
<span class="hljs-keyword">return</span> t &lt; <span class="hljs-number">14</span>
  ? i.default.readability.normal
  : n &gt;= <span class="hljs-number">10</span> &amp;&amp; n &lt; <span class="hljs-number">14</span>
    ? i.default.readability.hard
    : n &gt;= <span class="hljs-number">14</span> ? i.default.readability.veryHard 
      : i.default.readability.normal;
</code></pre>
<p>“Normal” is less than 14 words, “hard” is 10–14 words, and “very hard” is more than 14 words.</p>
<p>Now to find how to calculate the reading level.</p>
<p>I spent a while here trying to find any notion of how to calculate the reading level. I found it 4 lines above the <code>getReadabilityStyle</code> function.</p>
<pre><code class="lang-js">e = letters <span class="hljs-keyword">in</span> paragraph;
t = words <span class="hljs-keyword">in</span> paragraph;
n = sentences <span class="hljs-keyword">in</span> paragraph;

getReadingLevel: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">e, t, n</span>) </span>{
  <span class="hljs-keyword">if</span> (<span class="hljs-number">0</span> === t 
 <span class="hljs-number">0</span> === n) <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
  <span class="hljs-keyword">var</span> r = <span class="hljs-built_in">Math</span>.round(<span class="hljs-number">4.71</span> * (e / t) + <span class="hljs-number">0.5</span> * (t / n) - <span class="hljs-number">21.43</span>);
  <span class="hljs-keyword">return</span> r &lt;= <span class="hljs-number">0</span> ? <span class="hljs-number">0</span> : r;
}
</code></pre>
<p>That means your score is 4.71 <em> average word length + 0.5 </em> average sentence length -21.43. That’s it. That is how Hemingway grades each of your sentences.</p>
<h3 id="heading-other-interesting-things-i-found">Other Interesting Things I Found</h3>
<ul>
<li>The highlight commentary (information about your writing on the right hand side) is a big switch statement. Ternary statements are used to change the response based on how well you’ve written.</li>
<li>The grading goes up to 16 before it’s classed as “Post-Graduate” level.</li>
</ul>
<h3 id="heading-what-im-going-to-do-with-this">What I’m going to do with this</h3>
<p>I am planning to make a basic website and apply what I’ve learned from deconstructing the Hemingway app. Nothing fancy, more as an exercise for implementing some logic. I’ve built a Markdown previewer before, so I might also try to create a writing application with the highlighting and scoring system.</p>
<h1 id="heading-creating-my-own-hemingway-app">Creating My Own Hemingway App</h1>
<p>Having figured out how the Hemingway app works, I then decided to implement what I had learnt to make a much simplified version.</p>
<p>I wanted to make sure that I was keeping it basic, focusing on the logic more that the styling. I chose to go with a simple text box entry box.</p>
<h4 id="heading-challenges">Challenges</h4>
<ol>
<li><p>How to assure performance. Rescanning the whole document on every key press could be very computationally expensive. This could result in UX blocking which is obviously not what we want.</p>
</li>
<li><p>How to split up the text into paragraphs, sentences and words for highlighting.</p>
</li>
</ol>
<h4 id="heading-possible-solutions">Possible Solutions</h4>
<ul>
<li>Only rescan the paragraphs that change. Do this by counting the number of paragraphs and comparing that to the document before the change. Use this to find the paragraph that has changed or the new paragraph and only scan that one.</li>
<li><p>Have a button to scan the document. This massively reduces the calls of the scanning function.</p>
</li>
<li><p>Use what I learnt from Hemingway — every paragraph is a </p><p> and any sentences or words that need highlighting are wrapped in an internal <span> with the necessary class.</span></p>
</li>
</ul>
<h3 id="heading-building-the-app">Building the App</h3>
<p>Recently I’ve read a lot of articles about building a Minimum Viable Product (MVP) so I decided that I would run this little project the same. This meant keeping everything simple. I decided to go with an input box, a button to scan and an output area.</p>
<p>This was all very easy to set up in my index.html file.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">”stylesheet”</span> <span class="hljs-attr">href</span>=<span class="hljs-string">”index.css”</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Fake Hemingway<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Fake Hemingway<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span> <span class="hljs-attr">name</span>=<span class="hljs-string">””</span> <span class="hljs-attr">id</span>=<span class="hljs-string">”text-area”</span> <span class="hljs-attr">rows</span>=<span class="hljs-string">”10</span>"&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">”format()”</span>&gt;</span>Test Me<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">”output”</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">”index.js”</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Now to start on the interesting part. Now to get the Javascript working.</p>
<p>The first thing to do was to render the text from the text box into the output area. This involves finding the input text and setting the output’s inner html to that text.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">format</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">let</span> inputArea = <span class="hljs-built_in">document</span>.getElementById(“text-area”);
    <span class="hljs-keyword">let</span> text = inputArea.value;
    <span class="hljs-keyword">let</span> outputArea = <span class="hljs-built_in">document</span>.getElementById(“output”);
    outputArea.innerHTML = text;
}
</code></pre>
<p>Next is getting the text split into paragraphs. This is accomplished by splitting the text by ‘\n’ and putting each of these into a </p><p> tag. To do this we can map over the array of paragraphs, putting them in between </p><p> tags. Using template strings makes doing this very easy.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> paragraphs = text.split(“\n”);
<span class="hljs-keyword">let</span> inParagraphs = paragraphs.map(<span class="hljs-function"><span class="hljs-params">paragraph</span> =&gt;</span> <span class="hljs-string">`&lt;p&gt;<span class="hljs-subst">${paragraph}</span>&lt;/p&gt;`</span>);
outputArea.innerHTML = inParagraphs.join(“ “);
</code></pre>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*Nv9Mb4gnGQZTMmYReYb1HQ.png" alt="Image" width="902" height="675" loading="lazy"></p>
<p>Whilst I was working though that, I was becoming annoyed having to copy and paste the test text into the text box. To solve this, I implemented an Immediately Invoked Function Expression (IIFE) to populate the text box when the web page renders.</p>
<pre><code class="lang-js">(<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">start</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">let</span> inputArea = <span class="hljs-built_in">document</span>.getElementById(“text-area”);
    <span class="hljs-keyword">let</span> text = <span class="hljs-string">`The app highlights lengthy, …. compose something new.`</span>;
    inputArea.value = text;
})();
</code></pre>
<p>Now the text box was pre-populated with the test text whenever you load or refresh the web page. Much simpler.</p>
<h3 id="heading-highlighting">Highlighting</h3>
<p>Now that I was rendering the text well and I was testing on a consistent text, I had to work on the highlighting. The first type of highlighting I decided to tackle was the hard and very hard sentence highlighting.</p>
<p>The first stage of this is to loop over every paragraph and split them into an array of sentences. I did this using a <code>split()</code> function, splitting on every full stop with a space after it.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> sentences = paragraph.split(‘. ’);
</code></pre>
<p>From Heminway I knew that I needed to calculate the number of words and level of each of the sentences. The level of the sentence is dependant on the average length of words and the average words per sentence. Here is how I calculated the number of words and the total words per sentence.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> words = sentence.split(“ “).length;
<span class="hljs-keyword">let</span> letters = sentence.split(“ “).join(“”).length;
</code></pre>
<p>Using these numbers, I could use the equation that I found in the Hemingway app.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> level = <span class="hljs-built_in">Math</span>.round(<span class="hljs-number">4.71</span> * (letters / words) + <span class="hljs-number">0.5</span> * words / sentences — <span class="hljs-number">21.43</span>);
</code></pre>
<p>With the level and number of words for each of the sentences, set their difficulty level.</p>
<pre><code class="lang-js"><span class="hljs-keyword">if</span> (words &lt; <span class="hljs-number">14</span>) {
    <span class="hljs-keyword">return</span> sentence;
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (level &gt;= <span class="hljs-number">10</span> &amp;&amp; level &lt; <span class="hljs-number">14</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-string">`&lt;span class=”hardSentence”&gt;<span class="hljs-subst">${sentence}</span>&lt;/span&gt;`</span>;
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (level &gt;= <span class="hljs-number">14</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-string">`&lt;span class=”veryHardSentence”&gt;<span class="hljs-subst">${sentence}</span>&lt;/span&gt;`</span>;
} <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">return</span> sentence;
}
</code></pre>
<p>This code says that if a sentence is longer than 14 words and has a level of 10 to 14 then its hard, if its longer than 14 words and has a level of 14 or up then its very hard. I used template strings again but include a class in the span tags. This is how I’m going to define the highlighting.</p>
<p>The CSS file is really simple; it just has each of the classes (adverb, passive, hardSentence) and sets their background colour. I took the exact colours from the Hemingway app.</p>
<p>Once the sentences have been returned, I join them all together to make each of the paragraphs.</p>
<p>At this point, I realised that there were a few problems in my code.</p>
<ul>
<li>There were no full stops. When I split the paragraphs into sentences, I had removed all of the full stops.</li>
<li>The numbers of letters in the sentence included the commas, dashes, colons and semi-colons.</li>
</ul>
<p>My first solution was very primitive but it worked. I used split(‘symbol’) and join(‘’) to remove the punctuation and then appended ‘.’ onto the end. Whist it worked, I searched for a better solution. Although I don’t have much experience using regex, I knew that it would be the best solution. After some Googling I found a much more elegant solution.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> cleanSentence = sent.replace(<span class="hljs-regexp">/[^a-z0–9. ]/gi</span>, “”) + “.”;
</code></pre>
<p>With this done, I had a partially working product.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*aAQaw7iyax7r87qlh2i_sg.png" alt="Image" width="902" height="675" loading="lazy">
<em>Hard sentence highlighting</em></p>
<p>The next thing I decided to tackle was the adverbs. To find an adverb, Hemingway just finds words that end in ‘ly’ and then checks that it isn’t on a list of non-adverb ‘ly’ words. It would be bad if ‘apply’ or ‘Italy’ were tagged as adverbs.</p>
<p>To find these words, I took the sentences and split them into an arary of words. I mapped over this array and used an IF statement.</p>
<pre><code class="lang-js"><span class="hljs-keyword">if</span>(word.match(<span class="hljs-regexp">/ly$/</span>) &amp;&amp;, !lyWords[word] ){
    <span class="hljs-keyword">return</span> <span class="hljs-string">`&lt;span class=”adverb”&gt;<span class="hljs-subst">${word}</span>&lt;/span&gt;`</span>;
} <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">return</span> word
};
</code></pre>
<p>Whist this worked most of the time, I found a few exceptions. If a word was followed by a punctuation mark then it didn’t match ending with ‘ly’. For example, “The crocodile glided elegantly; it’s prey unaware” would have the word ‘elegantly;’ in the array. To solve this I reused the <code>.replace(/^a-z0-9. ]/gi,””)</code> functionality to clean each of the words.</p>
<p>Another exception was if the word was capitalised, which was easily solved by calling <code>toLowerCase()</code>on the string.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*iIvcSMYCHDp7Z5BhUnAogw.png" alt="Image" width="902" height="675" loading="lazy">
<em>Adverbs working</em></p>
<p>Now I had a result that worked with adverbs and highlighting individual words. I then implemented a very similar method for complex and qualifying words. That was when I realised that I was no longer just looking for individual words, I was looking for phrases. I had to change my approach from checking if each word was in the list to seeing if the sentence contained each of the phrases.</p>
<p>To do this I used the <code>.indexOf()</code> function on the sentences. If there was an index of the word or phrase, I inserted an opening span tag at that index and then the closing span tag after the key length.</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> qualifiers = getQualifyingWords();
<span class="hljs-keyword">let</span> wordList = <span class="hljs-built_in">Object</span>.keys(qualifiers);
wordList.forEach(<span class="hljs-function"><span class="hljs-params">key</span> =&gt;</span> {
    <span class="hljs-keyword">let</span> index = sentence.toLowerCase().indexOf(key);
    <span class="hljs-keyword">if</span> (index &gt;= <span class="hljs-number">0</span>) {
    sentence =
        sentence.slice(<span class="hljs-number">0</span>, index) +
        ‘&lt;span <span class="hljs-class"><span class="hljs-keyword">class</span></span>=”qualifier”&gt;’ +
        sentence.slice(index, index + key.length) +
        “&lt;/span&gt;” +
        sentence.slice(index + key.length);
    }
});
</code></pre>
<p>With that working, it’s starting to look more and more like the Hemingway editor.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*szV4gRH35rLe0xxRSgOxZw.png" alt="Image" width="902" height="675" loading="lazy">
<em>Getting complex phrases and qualifiers working</em></p>
<p>The last piece of the highlighting puzzle to implement was the passive voice. Hemingway used a 30 line function to find all of the passive phrases. I chose to use most of the logic that Hemingway implemented, but order the process differently. They looked to find any words that were in a list (is, are, was, were, be, been, being) and then checked whether the next word ended in ‘ed’.</p>
<p>I looped though each of the words in a sentence and checked if they ended in ‘ed’. For every ‘ed’ word I found, I checked whether the previous word was in the list of pre-words. This seemed much simpler, but may be less performant.</p>
<p>With that working I had an app that highlighted everything I wanted. This is my MVP.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*pgZcfGjZGkRiyE48v-UTOQ.png" alt="Image" width="902" height="675" loading="lazy">
<em>All the highlighting working</em></p>
<h3 id="heading-then-i-hit-a-problem">Then I hit a problem</h3>
<p>As I was writing this post I realised that there were two huge bugs in my code.</p>
<pre><code class="lang-js"><span class="hljs-comment">// from getQualifier and getComplex</span>
<span class="hljs-keyword">let</span> index = sentence.toLowerCase().indexOf(key);
<span class="hljs-comment">// from getPassive</span>
<span class="hljs-keyword">let</span> index = words.indexOf(match);
</code></pre>
<p>These will only ever find the first instance of the key or match. Here is an example of the results this code will produce.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*jKeU9Dn7Yu1XZn8YHUmh6w.png" alt="Image" width="928" height="555" loading="lazy">
<em>Code with bugs in</em></p>
<p>‘Perhaps’ and ‘been marked’ should have been highlighted twice each but they aren’t.</p>
<p>To fix the bug in getQualifier and getComplex, I decided to use recursion. I created a <code>findAndSpan</code> function which uses .<code>indexOf()</code> to find the first instance of the word or phrase. It splits the sentence into 3 parts: before the phrase, the phrase, after the phrase. The recursion works by passing the ‘after the phrase’ string back into the function. This will continue until there are no more instances of the phrase, where the string will just be passed back.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">findAndSpan</span>(<span class="hljs-params">sentence, string, type</span>) </span>{
    <span class="hljs-keyword">let</span> index = sentence.toLowerCase().indexOf(key);
    <span class="hljs-keyword">if</span> (index &gt;= <span class="hljs-number">0</span>) {
        sentence =
            sentence.slice(<span class="hljs-number">0</span>, index) +
            <span class="hljs-string">`&lt;span class="<span class="hljs-subst">${type}</span>"&gt;`</span> +
            sentence.slice(index, index + key.length) +
            <span class="hljs-string">"&lt;/span&gt;"</span> +
            findAndSpan(
                sentence.slice(index + key.length), 
                key,
                type);
    }
    <span class="hljs-keyword">return</span> sentence;
}
</code></pre>
<p>Something very similar had to be done for the passive voice. The recursion was in an almost identical pattern, passing the leftover array items instead of the leftover string. The result of the recursion call was spread into an array that was then returned. Now the app can deal with repeated adverbs, qualifiers, complex phrases and passive voice uses.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*15D7mV2ycniuDJ7As5en1A.png" alt="Image" width="928" height="647" loading="lazy"></p>
<h3 id="heading-statistics-counter">Statistics Counter</h3>
<p>The last thing that I wanted to get working was the nice line of boxes informing you on how many adverbs or complex words you’d used.</p>
<p>To store the data I created an object with keys for each of the parameters I wanted to count. I started by having this variable as a global variable but knew I would have to change that later.</p>
<p>Now I had to populate the values. This was done by incrementing the value every time it was found.</p>
<pre><code class="lang-js">data.sentences += sentence.length
or
data.adverbs += <span class="hljs-number">1</span>
</code></pre>
<p>The values needed to be reset every time the scan was run to make sure that values didn’t continuously increase.</p>
<p>With the values I needed, I had to get them rendering on the screen. I altered the structure of the html file so that the input box and output area were in a div on the left, leaving a right div for the counters. These counters are empty divs with an appropriate id and class as well as a ‘counter’ class.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">”adverb”</span> <span class="hljs-attr">class</span>=<span class="hljs-string">”adverb</span> <span class="hljs-attr">counter</span>”&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">”passive”</span> <span class="hljs-attr">class</span>=<span class="hljs-string">”passive</span> <span class="hljs-attr">counter</span>”&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">”complex”</span> <span class="hljs-attr">class</span>=<span class="hljs-string">”complex</span> <span class="hljs-attr">counter</span>”&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">”hardSentence”</span> <span class="hljs-attr">class</span>=<span class="hljs-string">”hardSentence</span> <span class="hljs-attr">counter</span>”&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">”veryHardSentence”</span> <span class="hljs-attr">class</span>=<span class="hljs-string">”veryHardSentence</span> <span class="hljs-attr">counter</span>”&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>With these divs, I used document.querySelector to set the inner html for each of the counters using the data that had been collected. With a little bit of styling of the ‘counter’ class, the web app was complete. <a target="_blank" href="https://samwsoftware.github.io/Projects/hemingway/">Try it out here</a> or look at <a target="_blank" href="https://github.com/SamWSoftware/Projects/tree/master/hemingway">my code here.</a></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*C1uc-HKl7IAjxXYDWWIWqQ.png" alt="Image" width="1379" height="695" loading="lazy">
<em>The completed app</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 7 important lessons about programming that I’ve learned at 17 ]]>
                </title>
                <description>
                    <![CDATA[ By Alec Jones Hey there, I’m Alec, I’m 17 years old, I’ve been learning web development since I was 12. I’m far from an excellent developer, but I’ve definitely learned some things about being an average one. ? Here are some lessons I’ve learned that... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/7-important-lessons-about-programming-that-ive-learned-at-17-516ae619686/</link>
                <guid isPermaLink="false">66c341994f1fc448a3678f66</guid>
                
                    <category>
                        <![CDATA[ coding ]]>
                    </category>
                
                    <category>
                        <![CDATA[ learning to code ]]>
                    </category>
                
                    <category>
                        <![CDATA[ lessons learned ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 23 May 2019 17:58:30 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/0*g_FeNjTZ2ZsfhD7_.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Alec Jones</p>
<p>Hey there, I’m Alec, I’m 17 years old, I’ve been learning web development since I was 12. I’m far from an excellent developer, but I’ve definitely learned some things about being an average one. ?</p>
<p>Here are some lessons I’ve learned that I think every developer, especially new developers, needs to know.</p>
<h3 id="heading-no-one-knows-everything">No one knows everything</h3>
<p>No developer knows everything and you don’t need to know everything.</p>
<p>There is so much more to being a developer than knowing by heart, for example, the methods of manipulating arrays in PHP version 5.6. It doesn’t matter if you know the little things, they are a google search away if you forget them.</p>
<p>There are far more important things you can do as a developer to improve yourself than learning these tiny insignificant details like,</p>
<ol>
<li>Improving your problem-solving skills</li>
<li>Improving your teamwork and communication skills</li>
<li>Increasing your knowledge of programming concepts and languages</li>
<li>Creating awesome projects to showcase your work</li>
<li>Focusing on writing clean efficient code</li>
</ol>
<p>The great thing about being a developer is that you don’t need to know everything. You only need to know how to solve problems.</p>
<h3 id="heading-having-bugs-is-essential-to-learning">Having bugs is essential to learning</h3>
<p><img src="https://cdn-media-1.freecodecamp.org/images/jvaqDDelHmG2CJlX7jgWwcyk77jGgB9NCdjW" alt="Image" width="600" height="315" loading="lazy">
_Source: [imgur](https://imgur.com/gallery/HTisMpC" rel="noopener" target="<em>blank" title=")</em></p>
<p>If you’re programming something and you’re not coming across any bugs, it means you’re learning nothing.</p>
<p>Not running into bugs does not mean that you’re somehow a great developer because you’re too smart to make a mistake. It means that you’ve already developed something similar, so many times, that you already know how not to run into the bugs.</p>
<p>When you’re solving bugs you are becoming a strong developer. There are endless bugs in development, so the faster you can learn to handle them, the better off you’ll be.</p>
<h3 id="heading-formal-education-is-not-necessary">Formal education is not necessary</h3>
<p>At 17, I’m currently grappling with this topic. Should I attend university so I can acquire a computer science degree?</p>
<p>That’s a tough question for me to answer. But, most people reading this are probably not 17, in fact, most of you probably already have a job.</p>
<p>If you have already attended college or university, you definitely do not need a computer science degree. You also don’t need to do all of these coding boot camps either.</p>
<p>A GitHub profile with some interesting projects on it speaks volumes. If you can demonstrate that you can program, it doesn’t matter what background you have.</p>
<p>It’s simply a question of how do you learn best.</p>
<p>I didn’t have the choice, I had to learn to code on weekends because I couldn’t take 6 weeks off of high school for a boot camp. ?‍♂️</p>
<p>If you want to go back to university to get a computer science degree or attend an 8-week boot camp, go for it. But it’s nowhere close to necessary.</p>
<h3 id="heading-googling-is-a-legitimate-skill">Googling is a legitimate skill</h3>
<p>If you want to be a great developer, you will need to enhance your googling ability. It’s essential to be able to find solutions and code that you are looking for.</p>
<p>There is frequent googling, especially when you’re learning a brand new technology.</p>
<p>There are <a target="_blank" href="https://www.scoopwhoop.com/google-search-tips/#.r4e31k357">many different ways to improve your search results</a> through little “hacks” and tips Google has set up.</p>
<p>Coding projects can take down weird rabbit holes of things you need to add to your code. Sometimes, you need to find a solution to a problem you don’t even understand. But thankfully, Google has the answer somewhere.</p>
<h3 id="heading-try-thinking-rather-than-coding">Try thinking rather than coding</h3>
<p>When you’re coding, do you ask yourself, “what’s the best way to write this code?”</p>
<p>I know I usually don’t until after I’ve written a subpar solution. Far too often, I find myself writing the solution that first popped into my head. Most of the time, the first solution to the problem isn’t the best.</p>
<p>The act of typing out the code is short. Anyone can write code quickly that will be sloppy. You need to take the time to come up with a good stable solution.</p>
<p>Though it can be tedious, test driven development promotes this greatly as you have to think about what functionality you expect and how it’ll work. You can’t freehand the code when you have to plan it ahead of time.</p>
<p>Of course, there are exceptions to every rule. I’m not saying you should sit quietly and think about every line of code.</p>
<p>But, with anything, save yourself the time of refactoring and bug fixing by thinking about your code.</p>
<h3 id="heading-be-careful-with-tutorials">Be careful with tutorials</h3>
<p>Following along with a coding tutorial is great for starting out, but I think these tutorials are not the only resource you should use for learning.</p>
<p>You’re not actually learning when you follow a coding tutorial. You may learn a little, but you’re not truly learning what you’re doing and why you’re doing it.</p>
<p>Additionally, these tutorials can also quickly skip over important parts of the code, as illustrated in Quincy’s tweet. It’s so easy to just copy and paste and not ask questions from the tutorial.</p>
<p>A far better way to learn to code is to set out on a project you’d like to build. Then, just get started. Find little pieces of code, write your own code, solve the bugs, read explanations and posts.</p>
<p>The most effective way to learn is to piece the puzzle together until you have a program that works.</p>
<h3 id="heading-tabs-are-better-than-spaces">Tabs are better than spaces</h3>
<p><img src="https://cdn-media-1.freecodecamp.org/images/D6kuyGtfBjJAHVMBwXKyj6ZhSXirPx4c-2CY" alt="Image" width="640" height="480" loading="lazy">
_[image source](https://www.youtube.com/watch?v=V7PLxL8jIl8" rel="noopener" target="<em>blank" title=")</em></p>
<p>I know. While you reading this article, you were thinking, “he’s got to be a spaces guy, it’s obvious.” I’m afraid not, everyone should be using tabs when they code.</p>
<p>I get it. Tabs can look different from other people’s computers. But, it’s so nice to just hit the tab, rather than smacking that space bar again and again. Treat yourself to tabs people!</p>
<p>Thanks for reading these short, but important, lessons that I’ve learned. If you disagree with any points I make, I’d love to hear why!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What I Learned from My First Contribution To Node.js Core ]]>
                </title>
                <description>
                    <![CDATA[ By Yael Hermon A couple of weeks ago my very first PR for Node.js core was merged! A few days later, I decided to tweet about it and share how positive this experience was, hoping to encourage others to contribute as well. Later, Uri Shaked suggested... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-i-learned-from-my-first-contribution-to-node-js-core-9cdc0e0d5efc/</link>
                <guid isPermaLink="false">66c3656c0002df282f2225c7</guid>
                
                    <category>
                        <![CDATA[ lessons learned ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ open source ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 26 Dec 2018 18:44:36 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*TMcOrpatfD5sTKioEqsMKg.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Yael Hermon</p>
<p>A couple of weeks ago my very first PR for Node.js core was merged! A few days later, I decided to tweet about it and share how positive this experience was, hoping to encourage others to contribute as well.</p>
<p>Later, <a target="_blank" href="https://www.freecodecamp.org/news/what-i-learned-from-my-first-contribution-to-node-js-core-9cdc0e0d5efc/undefined">Uri Shaked</a> suggested I share my experience in a short blog post. Uri always has great ideas. Thanks, Uri!</p>
<h4 id="heading-how-did-i-end-up-with-this-pr">How did I end up with this PR?</h4>
<p>I’m glad you asked. Let me start with a little background. I love Node.js, and contributing to it was actually on my bucket list for a really long time. I never got around to doing it because I always told myself that I didn’t have the time for it, or that I might not be qualified enough, or other lame excuses.</p>
<p>The plot twist happened when I was working on a talk for a JavaScript-Israel meetup about the <a target="_blank" href="https://docs.google.com/presentation/d/14CVuylg19RUnNLz525ecSHTyN7upVdF196WNtzhqdoA/edit?usp=sharing">V8 Garbage Collector</a>. <a target="_blank" href="https://github.com/benjamingr">Benjamin Gruenbaum</a>, a Node.js core collaborator, asked me if I would like him to connect me with V8 engineers to review my slides. Umm…<em>obviously</em> I would.</p>
<p>So he did, which turned out pretty awesome. Benji also asked me if I was interested in contributing to Node.js core. Again, I said yes. No more excuses. Stuff just got real.</p>
<h4 id="heading-setting-up-the-environment">Setting up the environment</h4>
<p>I first had to build Node.js on my machine. It was surprisingly easy, thanks to the <a target="_blank" href="https://github.com/nodejs/node/blob/master/BUILDING.md">great docs</a> Node.js has. Next, I decided to play around and start debugging it.</p>
<p>I’d be lying if I said it was smooth sailing from the start. The last time I worked with C++ was back in 2012. I was rusty. Moreover, back then I had a completely different environment than I have now. I had a Windows PC with Visual Studio on it, while now I am running VSCode on a Mac.</p>
<p>I love VSCode so I wanted to setup VSCode for this project too. I soon found an <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools">extension</a> and configured things to work. For my debugging configuration, I ended up setting up a node debugger and a lldb debugger to attach to the Node process. That worked great.</p>
<h4 id="heading-working-on-an-actual-issue">Working on an actual issue!</h4>
<p>So Benji connected me with <a target="_blank" href="https://github.com/addaleax">Anna</a>, who’s the Node.js core collaborator who implemented ‘<a target="_blank" href="https://nodejs.org/api/worker_threads.html">worker_threads</a>’. Benji also pointed me at this <a target="_blank" href="https://github.com/nodejs/node/issues/24636">issue</a>. I looked at the issue and tried reproducing it with as little code as possible, just to get rid of the noise.</p>
<p>I struggled with creating a test case that reproduced the issue, since it was caused by a race condition. The code that failed when running inside Node.js wouldn’t fail in my testing environment. Eventually, I found something that failed on all of my runs. Although it might not fail on every machine, or every time, Anna confirmed it was good enough. Next, I started debugging it to see what was actually happening there.</p>
<p>If you’ve never heard of ‘worker threads’, that’s probably because they are quite new and are currently in an experimental state. Workers let you create multiple environments running on independent threads. They are useful for performing CPU-intensive JavaScript operations, without blocking the main thread.</p>
<p>The main thread and the worker thread can communicate with each other through a message channel between them. In addition to this message channel, there is another message channel where internal messages are sent, such as stdout of the worker. When you <code>console.log</code> inside the worker, it arrives to the main thread through this internal message channel and the main thread handles it by pushing it to its stdout stream.</p>
<p>The problem was that we were calling the <code>kDispose</code> function in the JS worker class before waiting for all messages from worker’s stdio to be processed by the main thread through the internal message port. So when the worker thread finished, we lost the references for the parent side stdio streams, and a message to the parent could possibly arrive after that.</p>
<p>At first, I tried lots of different approaches to getting this fixed, including setting a promise to be resolved when the message port was done, awaiting it before disposing, and passing JS callbacks to the C++ layer.</p>
<p>Chatting with Anna about it revealed to me that a <em>drain</em> method existed for the MessagePort and it emitted all its incoming messages synchronously. So in the end, all the messages from it would be processed. In fact, <em>drain</em> was already called for the external MessagePort. How hadn’t I seen this function all this time? ? I added a call to d<em>rain</em> also on the internal MessagePort. The fix was that simple.</p>
<p>An important thing to remember is — it’s totally fine trying out weird approaches along the way. That’s how you learn. And after debugging lots of worker_threads code, I can say that I know some of its codebase pretty well now :)</p>
<p>Benji and Anna were so welcoming right from the beginning. This was a great experience. I learned a lot from Anna and from the code, which was very challenging. It’s definitely not something I usually deal with in my day-to-day.</p>
<p>I can’t wait to work on my next issue!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ The unforgettable lessons I’ve learned from 100 boring conferences ]]>
                </title>
                <description>
                    <![CDATA[ By Daniel Burka I’ve been to many conferences over the last twenty years. Mostly the speakers droned on about their topics, which were easily forgotten. Thinking back, only a few big ideas really stuck with me. These are three ideas I’ve come back to... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/3-unforgettable-lessons-i-learned-from-100-boring-conferences-7a509261e617/</link>
                <guid isPermaLink="false">66c3415c0bafa8455505c634</guid>
                
                    <category>
                        <![CDATA[ Design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ lessons learned ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Life lessons ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Public Speaking ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 28 Jun 2018 19:17:05 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*ZvFo5820uRt81HaetfIFEg.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Daniel Burka</p>
<p>I’ve been to many conferences over the last twenty years. Mostly the speakers droned on about their topics, which were easily forgotten. Thinking back, only a few big ideas really stuck with me. These are three ideas I’ve come back to over and over again in my career.</p>
<h3 id="heading-there-is-a-big-difference-between-designed-well-and-well-designed"><strong>There is a big difference between designed well and <em>well-designed.</em></strong></h3>
<p>Graphic design legend <a target="_blank" href="http://www.davidcarsondesign.com/">David Carson</a> gave a tedious presentation at one of the first conferences I ever attended. However, fifteen years later, I still clearly remember a pair of slides from his talk that looked something like this:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/MhxPeDF5ayRwySTzaG9U0efzLHfbCPIwlHIf" alt="Image" width="800" height="393" loading="lazy">
_(photo credits [Bernard Hermant](https://www.flickr.com/photos/stml/3947231477/in/photolist-71NAp8-wSwLaQ-BTHab-mjzdvc-57nyDQ-oU1YMo-7RewhE-6D7qMk-6kfL4o-69XaF-6j8Nkf-bKFqj8-65RPHK-s94ZWv-8z8pYS-6EqKew-6VsTUn-9zYac8-iaRSMQ-dHQqFh-dzKeKM-4zdjFS-6QbtXK-pv9icm-6MSt5M-6gaaae-59T7WL-7HG2uA-9zCa75-78mVco-ban3Wk-6KNV9h-cZFmQh-dpPcsC-VQzu4u-Vkbu3b-5RFCC1-AvRuS-dmLia3-ahdrAT-bQh6LR-SfygU9-9wfKvR-fEqwDw-dKRVsu-9qhz2x-26JPXgA-7GihBU-3KkkXa-HYHfEe" rel="noopener" target="_blank" title=""&gt;STML and &lt;a href="https://unsplash.com/photos/aAEpfi8f59Y" rel="noopener" target="<em>blank" title="))</em></p>
<p>There is a chasm between a concept that looks professionally designed versus a design that truly communicates your message.</p>
<p>The sign on the left says, “Please don’t park here, thanks.” The sign on the right says, “Try parking here PUNK and I’ll rip your head off your shoulders.” The second sign says a lot in just a few strokes. It’s more effective. It’s better designed.</p>
<p>Q: Which <em>No parking</em> sign would you obey?<br>A: The one tagged by the axe-wielding psychopath.</p>
<h3 id="heading-take-powerpoint-design-seriously"><strong><em>Take PowerPoint design seriously.</em></strong></h3>
<p>Yeah, you read that right. Over a decade ago, I heard a design executive from Adobe talk about how she got her start. She explained how, during the first few years of her career, she was bored to death designing slides for her bosses. Regardless, she took to the task with an open heart and poured her energy into designing the best damn PowerPoint slides.</p>
<p>In the process, she developed communication skills that served her well later on…and more importantly, an attitude that every design challenge is worthy of her effort. Amen.</p>
<blockquote>
<p>PS: I wish I could remember her name or at least where I saw her speak. If you know who she might be, please share. I’d love to credit her and personally say thank you.</p>
</blockquote>
<h3 id="heading-dont-take-advice-from-speakers-at-conferences"><strong><em>Don’t take advice from speakers at conferences.</em></strong></h3>
<p>To put it politely, TechCrunch founder <a target="_blank" href="https://en.wikipedia.org/wiki/Michael_Arrington">Michael Arrington</a> is loud. When he waltzed onto the stage five minutes late with a talk on “15 Important Lessons for Entrepreneurs”, I was ready to dismiss whatever he was about to say. But to my surprise, the first <em>important lesson</em> held a lot of truth.</p>
<p>Mike addressed the sea of heads: “If you’re going to start the next big thing, don’t listen to anything that I’m about to say.” Out of context, that sounds extreme. However, the way I interpreted Mike’s comment is:</p>
<p>Conference speakers confidently dole out lessons based on what worked well for them. What worked well for them is only ONE path, not the ONLY path. Your way may be fundamentally different, and that’s GREAT. Few people accomplished great things by copying what others have done.</p>
<p>In short, take every damn thing you hear at a conference with a huge shovel-full of salt. Then go find your own path.</p>
<p>Which lessons actually stuck with you from presentations over the years? I’d love to hear your story in the comments…</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
