<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Henrique Inonhe</title>
    <description>The latest articles on DEV Community by Henrique Inonhe (@henriqueinonhe).</description>
    <link>https://dev.to/henriqueinonhe</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F640594%2F7007af3b-b10c-47ea-98e4-b277c2e8b1de.jpeg</url>
      <title>DEV Community: Henrique Inonhe</title>
      <link>https://dev.to/henriqueinonhe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/henriqueinonhe"/>
    <language>en</language>
    <item>
      <title>Using Diff to Help My Girlfriend Catch Cheating Students</title>
      <dc:creator>Henrique Inonhe</dc:creator>
      <pubDate>Thu, 09 Sep 2021 01:36:17 +0000</pubDate>
      <link>https://dev.to/henriqueinonhe/using-diff-to-help-my-girlfriend-catch-cheating-students-2d90</link>
      <guid>https://dev.to/henriqueinonhe/using-diff-to-help-my-girlfriend-catch-cheating-students-2d90</guid>
      <description>&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@anniespratt?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Annie Spratt&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/JexAuNCfefs?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Backstory
&lt;/h2&gt;

&lt;p&gt;My girlfriend teaches Portuguese to teens ranging from 10 to 14 years old (we live in Brazil, mind you, so, Portuguese classes here are analogous to English classes in US/UK).&lt;/p&gt;

&lt;p&gt;Due to this whole pandemic situation, there are some students still taking classes at home, which eventually also includes doing &lt;strong&gt;tests&lt;/strong&gt; at home as well.&lt;/p&gt;

&lt;p&gt;As it isn't feasible to supervise students when they are taking these tests, cheating has become a much bigger problem, not only because students may look for answers at the internet or share them with one another, but also because as these tests are applied via online forms, copying and pasting answers are much easier.&lt;/p&gt;

&lt;p&gt;Now here comes the funny part: you'd think that these students, when sharing answers with one another, would at the very least &lt;strong&gt;rewrite&lt;/strong&gt; them with their own words as a way to disguise their cheating attempt, but what they did instead was mostly &lt;strong&gt;copy and paste&lt;/strong&gt; answers with little to no modifications!&lt;/p&gt;

&lt;p&gt;By noticing this pattern she could then start to identify cheaters.&lt;/p&gt;

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

&lt;p&gt;If you want to find out whether a given student has shared his answers with other colleagues, you'd have to compare his test with each one of the other students' tests, and then &lt;strong&gt;repeat this process for each student&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;There are about 50 students that took these tests, which means that the first test is compared with the other 49 tests, the second test doesn't need to be compared with the first one, but still has to be compared with the remaining 48 tests, and so on.&lt;/p&gt;

&lt;p&gt;We're basically dealing with the sum of the terms of an arithmetic progression with ratio 1 so, if we have &lt;em&gt;n&lt;/em&gt; students, then we'll need to perform &lt;em&gt;(n^2 - n)/2&lt;/em&gt; comparisons.&lt;/p&gt;

&lt;p&gt;For 50 students this amounts to 1225 comparisons and considering the test has 5 questions, then we're talking 6125 comparisons.&lt;/p&gt;

&lt;p&gt;Cleary, doing all these comparisons by hand would be a very tedious and time consuming task, but thankfully she is dating a programmer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;At first sight, comparing sentences may seem quite simple as our first instinct might be to compare them character by character, this however, is not a good approach as even if we treated these sentences before comparing them (by removing leading/trailing spaces between words, converting them to lowercase, etc) the only thing it can do is either tell us whether the two answers are the same or not.&lt;/p&gt;

&lt;p&gt;This naive approach has no gradient, no nuance, it only gives us a "yes" or "no" answer to the question of whether the sentences are equal, but can't tell us how &lt;strong&gt;similar&lt;/strong&gt; they are, and it only takes a miniscule difference between them to turn a "yes" into a "no".&lt;/p&gt;

&lt;p&gt;Thus, we need a better way to do this.&lt;/p&gt;

&lt;p&gt;Turns out there's a very neat algorithm called LCS (Longest Common Subsequence) which is perfect for this job and that programmers use almost every day as it is the basis for the &lt;strong&gt;diff&lt;/strong&gt; algorithm, which is used extensively in &lt;strong&gt;git&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For instance, suppose the question is "Why do we need to wash our hands before eating?" and one answer is "Because there are microorganisms that when ingested may harm us" and the other is "We wash our hands because there are microorganisms that when ingested might harm us".&lt;/p&gt;

&lt;p&gt;These two answers are worded in a very similar way, which might indicate a cheating attempt has taken place; however they are not exactly equal as the second answer is prepended by the question and exchanges the word "may" for "might".&lt;/p&gt;

&lt;p&gt;The naive approach would flag these answers as different and wouldn't be able to notice that the second answer, even though it is not exactly equal to the first, it is a slight variation of it.&lt;/p&gt;

&lt;p&gt;That is why LCS come in handy, as it has a much cleverer way of comparing sentences, and when run at word level for the aforementioned sentences, yields this:&lt;/p&gt;

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

&lt;p&gt;The words in &lt;strong&gt;black&lt;/strong&gt; are the ones that are common to &lt;strong&gt;both answers&lt;/strong&gt;, the ones in &lt;strong&gt;green&lt;/strong&gt; are the ones that were &lt;strong&gt;added&lt;/strong&gt; to the second answer and the ones in &lt;strong&gt;red&lt;/strong&gt; are the ones that were &lt;strong&gt;removed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Notice that this algorithm not only tells us which words are common, were added or removed, but it also tells us &lt;strong&gt;where&lt;/strong&gt; these &lt;strong&gt;insertions&lt;/strong&gt; and &lt;strong&gt;deletions&lt;/strong&gt; took place.&lt;/p&gt;

&lt;p&gt;Back to the tests, on the one hand, applying them via online forms makes it easier to cheat but on the other hand it also makes it possible to export answers as a CSV file, which for the uninitiated is in many ways like an excel/spreadsheet file, and, most importantly, very easy to manipulate using programming.&lt;/p&gt;

&lt;p&gt;With this in mind, once I had all the answers exported as a CSV file all I did was run the LCS algorithm and then present the results in a very simple web page so that it was easier to visually inspect them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;In order to respect the students privacy I won't be able to show you the actual data, but still there are a lot of interesting things that can be said without incurring privacy violations.&lt;/p&gt;

&lt;p&gt;The first thing we noticed is that there are mainly two kinds of questions: the ones that have an "exact answer" and thus whose answers have little to no variation and the ones whose answer may be worded in various different ways.&lt;/p&gt;

&lt;p&gt;Of course, there's no way to know if there were cheating attempts for the first kind so we'll concentrate on the second.&lt;/p&gt;

&lt;p&gt;For questions of the second kind even though most times there is a right answer for them (i.e. they are not open ended questions) almost all answers were worded in a completely different way.&lt;/p&gt;

&lt;p&gt;Obviously there are some sequences of words that are common to all of them but nevertheless the "core" of each answer varies greatly from one another.&lt;/p&gt;

&lt;p&gt;In the cases where answers were almost or exactly equal, we were afraid of relying on this fact alone as it could be pointing us to a false positive, given that there was the very unlikely yet non zero possibility that these answers were equal by pure chance.&lt;/p&gt;

&lt;p&gt;However, upon further investigation, it was discovered that every time a set of equal answers was found, the authors of these answers were closely related (e.g. brothers, sisters, close friends) and some of them were already known for previous cheating attempts.&lt;/p&gt;

&lt;p&gt;With all this information my girlfriend was then able to successfully identify all cheating attempts (or at least the most blatant ones).&lt;/p&gt;

&lt;p&gt;Now, regarding what happened to the cheaters, I'm not allowed to disclose this information, but let's just say that they weren't very happy, nor were their parents.&lt;/p&gt;

</description>
      <category>diff</category>
      <category>lcs</category>
    </item>
    <item>
      <title>Frontend Environment Variables – What, Why and How</title>
      <dc:creator>Henrique Inonhe</dc:creator>
      <pubDate>Sun, 05 Sep 2021 14:58:24 +0000</pubDate>
      <link>https://dev.to/henriqueinonhe/frontend-environment-variables-what-why-and-how-1c1</link>
      <guid>https://dev.to/henriqueinonhe/frontend-environment-variables-what-why-and-how-1c1</guid>
      <description>&lt;p&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/@debrupas?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Pascal Debrunner&lt;/a&gt; on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;If you ever touched backend code you probably already know that environment variables really come in handy when dealing with multiple environments, like local, dev, qa, prod by decoupling configuration from code.&lt;/p&gt;

&lt;p&gt;In case you didn't, you may think of environment variables as &lt;strong&gt;inputs&lt;/strong&gt; that you application take as parameters, after all, a program is pretty much like a function, with inputs, outputs and sometimes side effects.&lt;/p&gt;

&lt;p&gt;So, just as with functions, where parametrizing values that were previously hardcoded in the function's body yields a more flexible implementation, we may extract &lt;strong&gt;hardcoded values&lt;/strong&gt; from our frontend code as &lt;strong&gt;environment variables&lt;/strong&gt;, so that we are able to change our application behavior without touching the code itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why
&lt;/h2&gt;

&lt;p&gt;When working with a real project you'll probably deal with multiple environments (local, dev, qa, prod) and each of these environments will most likely have its own dedicated API service, and thus each one will be accessed using a different URL.&lt;/p&gt;

&lt;p&gt;So instead of hardcoding the API URL, we read this value from an environment variable so that we can deploy the same code for all these different environments.&lt;/p&gt;

&lt;p&gt;Another interesting use case for environment variables is to implement &lt;strong&gt;feature flags&lt;/strong&gt; which are used to enable or disable certain features depending on the context (e.g. A/B testing or the application might serve multiple countries/regions and some features might not be available in some of them).&lt;/p&gt;

&lt;p&gt;Currently at the place I work we also rely on environment variables to set the "check for updates" polling interval and to tweak some testing scenarios.&lt;/p&gt;

&lt;p&gt;In summary, environment variables are a widely supported way of decoupling &lt;strong&gt;configuration&lt;/strong&gt; from &lt;strong&gt;code&lt;/strong&gt;. (See &lt;a href="https://12factor.net/config"&gt;12factorapp&lt;/a&gt; for an in depth explanation)&lt;/p&gt;

&lt;h2&gt;
  
  
  How
&lt;/h2&gt;

&lt;p&gt;If we were talking about environment variables at the backend we could just &lt;code&gt;npm install dotenv&lt;/code&gt; and &lt;code&gt;dotenv.config()&lt;/code&gt; and then call it a day.&lt;/p&gt;

&lt;p&gt;However, as the frontend runs on the client's machine it can't access environment variables (and even if it could, it would make no sense), so we need a different approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enter the compiler
&lt;/h3&gt;

&lt;p&gt;As reading environment variables at &lt;strong&gt;run time&lt;/strong&gt; is not an option for the frontend, we must fallback to &lt;strong&gt;compile time&lt;/strong&gt; substitution.&lt;/p&gt;

&lt;p&gt;Nowadays you'll most likely be using a compiler for the frontend, either because you're using JSX, or relying on Babel polyfills, or maybe you recognize the value of static type checking and need to transpile from Typescript.&lt;/p&gt;

&lt;p&gt;Even if you don't really care about any of those things, you'll probably be minifying your JS code to reduce the bundle size and get that perfect Page Speed (&lt;em&gt;is this still relevant?&lt;/em&gt;) score.&lt;/p&gt;

&lt;p&gt;What we're going to do then is use the compiler to substitute environment variables in the code by their actual values at &lt;strong&gt;build/compile time&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this example I'll be using &lt;strong&gt;Webpack&lt;/strong&gt; as it is the standard bundler.&lt;/p&gt;

&lt;p&gt;So, supposing you already have your build configuration in place with Webpack, setting up environment variables is a 3-step process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//webpack.config.js&lt;/span&gt;

&lt;span class="c1"&gt;//1. Read environment variables from our .env file&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;dotenv&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;dotenv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;//2. List environment variables you'll use&lt;/span&gt;
&lt;span class="c1"&gt;// The keys listed here are the ones that will&lt;/span&gt;
&lt;span class="c1"&gt;// be replaced by their actual value in the code.&lt;/span&gt;
&lt;span class="c1"&gt;// Also, their presence will be validated, so that&lt;/span&gt;
&lt;span class="c1"&gt;// if they're undefined webpack will complain and&lt;/span&gt;
&lt;span class="c1"&gt;// refuse to proceed with compilation&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;environmentVariables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;API_BASE_URL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CHECK_FOR_UPDATES_TIME_INTERVAL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="c1"&gt;//3. Use Webpack's EnvironmentPlugin&lt;/span&gt;
&lt;span class="nl"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;webpack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EnvironmentPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;environmentVariables&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then you can use environment variables the same way you'd do with backend code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;API_BASE_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/login`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once again it is very important to keep in mind that what actually happens is essentially &lt;strong&gt;textual substitution&lt;/strong&gt; of environment variables in build time, and a fortunate consequence of this is  that for some cases like with feature flags, the minification process is even able to completely wipe out unreachable code branches, eliminating code related to unused features.&lt;/p&gt;

&lt;p&gt;By the way, if you ever programmed with C or C++, this substitution process works pretty much the same way the C/C++ preprocessor would when you're using &lt;code&gt;#define&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>javascript</category>
      <category>webpack</category>
      <category>environment</category>
    </item>
  </channel>
</rss>
