<?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: Oluwole Ajewole</title>
    <description>The latest articles on DEV Community by Oluwole Ajewole (@wolemercy).</description>
    <link>https://dev.to/wolemercy</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%2F680829%2F226455c6-15ce-444e-994e-39b89c800a64.jpeg</url>
      <title>DEV Community: Oluwole Ajewole</title>
      <link>https://dev.to/wolemercy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wolemercy"/>
    <language>en</language>
    <item>
      <title>Scripting The Monty Hall Problem</title>
      <dc:creator>Oluwole Ajewole</dc:creator>
      <pubDate>Mon, 08 Nov 2021 06:08:26 +0000</pubDate>
      <link>https://dev.to/wolemercy/scripting-the-monty-hall-problem-5d5g</link>
      <guid>https://dev.to/wolemercy/scripting-the-monty-hall-problem-5d5g</guid>
      <description>&lt;p&gt;Ahoy!&lt;/p&gt;

&lt;p&gt;If like me your eyes glisten and your ears perk up when you come across deceptive math puzzles, you are sure to find some value in this piece. Here, I introduce the Monty Hall problem, discuss a useful way to think about the solution, and present a python script I wrote to validate it.&lt;/p&gt;

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

&lt;p&gt;The Monty Hall problem (named after Monty Hall, a game show host) is a rather deceptive brain teaser that became somewhat popular towards the end of the 20th Century. It is not a difficult problem to understand as it contains very simple premises but it is, nevertheless, pretty tricky to solve. &lt;/p&gt;

&lt;p&gt;Like the Ball And Bat Problem, psychologists often use the Monty Hall problem to illustrate how easily humans can fail to grasp the "math" or the "rational", opting instead for the "immediately obvious" or "intuitive" response. They call out our tendency to introduce bias and other forms of heuristics when making decisions—preferring easier, less laborious, and inaccurate approaches to more tasking, and more accurate ones. &lt;/p&gt;

&lt;p&gt;What I find most amusing and fascinating about such problems that is that we are usually very aware that they are tricky problems—tricky problems that we are probably hearing about because they've most likely conquered the minds of many people. Yet, we dive in to answer them, optimistic that we'd give a correct response. But of course, we are usually wrong—like I and most people were with the Monty Hall Problem. And even when we are presented with the correct answer, it could be pretty difficult to wrap our heads around the right answer.&lt;/p&gt;

&lt;p&gt;The Monty Hall problem tests our understanding of probabilities in some sort of illusory manner. Here is my  variant of the problem:&lt;/p&gt;

&lt;p&gt;Say you are Luffy, a pirate searching for the grandest treasure—The One Piece. Say there are three identical maps, one of which leads you to the treasure. The other two maps lead you to a wasteland filled with sand. Of course you want the treasure, but you don't know which of the three maps has the treasure. You can't differentiate one from the other.&lt;/p&gt;

&lt;p&gt;Say the maps have a custodian, Monty Hall, and he knows what map leads where. In other words, Monty Hall knows which maps lead you to a wasteland and the one that can guide you to the treasure. He decides to play a game with you as follows;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You are to pick any one of the three maps (at this point, you don't know if your chosen map leads you to the treasure or to a wasteland)&lt;/li&gt;
&lt;li&gt;Next, of the other two maps, Monty Hall picks one map that leads to a wasteland. Remember, he knows where each map leads to and he always picks a wasteland map.&lt;/li&gt;
&lt;li&gt;At this point you have picked one map (that may or may not lead to the treasure) and Monty Hall has picked a map that definitely leads to the wasteland. Monty's map needn't be considered anymore, but there is a third map that neither of you chose.&lt;/li&gt;
&lt;li&gt;Next, Monty Hall asks you; do you want to stick with your initial selection or do you want to switch your selection to the third map?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the problem statement. You are given a choice to stick with your initial map selection or switch to the third map that neither of you chose. Will you stick or switch?&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%2Fjlgj5nyus9f3cmo7nacz.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%2Fjlgj5nyus9f3cmo7nacz.png" alt="Luffy befuddled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;The Answer&lt;/h2&gt;

&lt;p&gt;With little or no deliberation, we are tempted to choose to stick with our original decision. This is because we believe that switching to the third map would not change the odds that we chose the right map. Our mind is heavily focused on the probability that our first choice was correct, and switching seems like an unnecessary risk. We could also think, perhaps, that after that after Monty Hall chooses the second map, the probability that our original selection is the treasure map is equal to the probability that the third map is the treasure map, i.e. 1/2 each since there are now two options. So there is no point switching. But that is not so!&lt;/p&gt;

&lt;p&gt;It may take some time to sink in, but here is what I consider a useful approach to analysing the problem;&lt;/p&gt;

&lt;p&gt;At the start, when you make the first selection &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the probability of picking a treasure map is 1/3;&lt;/li&gt;
&lt;li&gt;and the probability of picking a wasteland map is 2/3&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words, you are more likely to pick a wasteland map than a treasure map.&lt;/p&gt;

&lt;p&gt;Next, regardless of your choice, Monty Hall will always pick a wasteland map. &lt;/p&gt;

&lt;p&gt;After Monty picks, there are two possible scenarios; either the third unselected map is the treasure map or it is another wasteland map. And these two scenarios play out probabilistically in relation to your first choice in the following ways;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if the third unselected map is a wasteland map, it must mean that your first selection was the treasure map. This happens one-third of the time (1/3) as stated above. And therefore, you'd win if you don't switch&lt;/li&gt;
&lt;li&gt;if the third unselected map is the treasure map, it must mean that your first selection was a wasteland map. This happens two-thirds of the time (2/3) as stated above. And therefore, you'd win if you switch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As such, since your first selection is likely to be a wasteland map than the treasure map, it makes statistical sense to always switch to the third map. Of course, winning is not guaranteed by switching. But you are twice as likely to win when you switch than when you stick to your first selection. So always switch!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Python Script: Some Evidence
&lt;/h2&gt;

&lt;p&gt;It is normal to still have doubts about the solution to the Monty Hall problem. A useful way to perhaps, cement your belief in and acceptance of the answer is to simulate the problem several times. This is exactly what I did with using a Python Script. You can find the gist &lt;a href="https://gist.github.com/Wolemercy/3d26cb6ad5b9a9c18a819121e78b0346" rel="noopener noreferrer"&gt;here&lt;/a&gt; and the repo &lt;a href="https://github.com/Wolemercy/monty-hall" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Let's walk through the code;&lt;/p&gt;

&lt;p&gt;First we import the &lt;code&gt;random&lt;/code&gt; module. We define a function called &lt;code&gt;single run&lt;/code&gt; that initializes our map trio as an array. We select a random map to contain our One Piece treasure and the function returns the map array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# The Monty Hall Problem

import random

# Instantiating a random treasure map
def single_run():
    maps = ['wasteland', 'wasteland', 'wasteland']
    treasure_index = random.randint(0, 2)
    maps[treasure_index] = 'one piece'
    return maps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we define a function that returns Luffy's random first choice&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Luffy's first choice
def luffy():
    luffy_first_choice = random.randint(0, 2)
    return luffy_first_choice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we define a function that returns Monty's choice of a wasteland map. We use a while loop to ensure that Monty's chosen map is neither Luffy's first choice nor the treasure map.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Monty's choice of a location that is neither Luffy's choice nor the treasure location
def monty(maps, luffy_first_choice):
    monty_choice = 0

    while monty_choice == luffy_first_choice or maps[monty_choice] == 'one piece':
        monty_choice += 1

    return monty_choice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we define a function that returns Luffy's switched choice. Note that this function is not necessary for the simulation. I only included it for the sake of completeness.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# switch Luffy's choice
def luffy_switch(luffy_first_choice, monty_choice):

    luffy_switch_choice = 0

    while luffy_switch_choice == luffy_first_choice or luffy_switch_choice == monty_choice:
        luffy_switch_choice += 1

    return luffy_switch_choice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we define a function that returns the output. It accepts as input, the number of times switching yielded the treasure map, the number of times sticking yielded the treasure map, and the number of trials. It returns the percentages for both decisions as part of a string.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# output to be displayed
def output(stick, switch, trials):
    stick_percent = round((stick/trials) * 100)
    switch_percent = round((switch/trials) * 100)

    print(f'Luffy found One Piece {stick_percent} % of the time when he decided to stick to his initial choice ')
    print(f'Luffy found One Piece {switch_percent} % of the time when he decided to switch his initial choice')

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

&lt;/div&gt;



&lt;p&gt;And we have the body of the script. It accepts the number of trials as input, i.e. the number of simulations you want to run. We also initialize the number of  times sticking and switching yield the treasure map to zero. &lt;/p&gt;

&lt;p&gt;We run our loop as many times as the number of trials. Inside the  loop, we use are already defined functions to;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;get the maps array&lt;/li&gt;
&lt;li&gt;randomly make Luffy's initial map choice&lt;/li&gt;
&lt;li&gt;make Monty choose a wasteland map&lt;/li&gt;
&lt;li&gt;switch Luffy's initial choice&lt;/li&gt;
&lt;li&gt;increment the &lt;code&gt;stick_count&lt;/code&gt; if the initial choice has the One Piece treasure&lt;/li&gt;
&lt;li&gt;increment the &lt;code&gt;switch_count&lt;/code&gt; if the switched choice has the One Piece treasure
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;print('The Monty Hall Problem')
trials = int(input('Enter the number of trials:  '))

# Luffy sticks
stick_count = 0

# Luffy switches
switch_count = 0

for i in range(trials):
    maps = single_run()
    luffy_first_choice = luffy()
    monty_choice = monty(maps, luffy_first_choice)
    luffy_switch_choice = luffy_switch(luffy_first_choice, monty_choice)

    if maps[luffy_first_choice] == 'one piece':
        stick_count += 1

    elif maps[luffy_switch_choice] == 'one piece':
        switch_count += 1

output(stick_count, switch_count, trials) 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note, as mentioned earlier, that we don't need the &lt;code&gt;luffy_switch&lt;/code&gt; function, and by implication we can do without incrementing the &lt;code&gt;switch_count&lt;/code&gt; as we have done. That's because we are  sure that if Luffy's initial choice was the treasure map, then the third choice is definitely not the treasure map. In the same vein, if Luffy's initial choice wasn't the treasure map, then the third choice that could have been switched to would be the treasure map. &lt;/p&gt;

&lt;p&gt;In other words, the treasure map is either the original choice or the switched choice. The incidences of both (&lt;code&gt;stick_count&lt;/code&gt; and &lt;code&gt;switch_count&lt;/code&gt; ) necessarily add up to the number of trials. So we can use simple arithmetic to evaluate one if we have the other; &lt;code&gt;switch_count = trials - stick_count&lt;/code&gt;. That's definitely a more concise way of writing this script. I only wrote it this way for the sake of completeness.&lt;/p&gt;

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

&lt;p&gt;The result of running the Python Script (several times) proves that Luffy gets the treasure map about two-thirds (2/3) of the time when he switches as opposed to one-third (1/3) of the time when he sticks with his original choice.&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%2Fmx4egob8t1vhoyg2igb6.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%2Fmx4egob8t1vhoyg2igb6.png" alt="Monty Hall script terminal output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that's The Monty Hall Problem. The key thing to remember is to always switch maps after Monty Hall chooses a wasteland map because your initial choice was more likely wrong than correct. As such, switching improves the chances that you'd win the treasure map. &lt;/p&gt;

&lt;p&gt;And when you find the treasure, remember to share it with me! A comment, a like, a repost, some feedback—anything will do!&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;br&gt;
Also connect with me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LinkedIn: &lt;a href="https://www.linkedin.com/in/wolemercy" rel="noopener noreferrer"&gt;Wolemercy&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Twitter:  &lt;a href="https://twitter.com/wolemercy" rel="noopener noreferrer"&gt;Wolemercy&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/Wolemercy" rel="noopener noreferrer"&gt;Wolemercy&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>sideprojects</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Building A URL Shortener Application</title>
      <dc:creator>Oluwole Ajewole</dc:creator>
      <pubDate>Tue, 10 Aug 2021 11:15:49 +0000</pubDate>
      <link>https://dev.to/wolemercy/building-a-url-shortener-application-5clb</link>
      <guid>https://dev.to/wolemercy/building-a-url-shortener-application-5clb</guid>
      <description>&lt;p&gt;Welcome to my first of many #DEV posts!&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Development&lt;/li&gt;
&lt;li&gt;Deployment&lt;/li&gt;
&lt;li&gt;Lessons&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;As part of my dev growth, I thought I'd build an application that ticked the following boxes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;functionality: it should serve a specific purpose rather than just be a dummy&lt;/li&gt;
&lt;li&gt;usefulness: users should derive some meaningful merit from it &lt;/li&gt;
&lt;li&gt;instructiveness: it should be to me, an opportunity to learn and improve my software engineering skills&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course, there are other needs—in addition to the ones aforementioned—that applications should fulfil, but I reasoned it best to focus on those three for now. It resulted in me building a &lt;a href="https://weburlshortener.herokuapp.com/"&gt;&lt;strong&gt;URL Shortener App&lt;/strong&gt;&lt;/a&gt; that is scalable and ultimately, satisfying.&lt;/p&gt;

&lt;p&gt;This post is not a "How To" guide on recreating this application; rather,  it's a summary of the project, and the documentation of the things I learnt—or more aptly, the things I learnt and still remember😅.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Stack
&lt;/h3&gt;

&lt;p&gt;The core aspects of the project as well as the elements associated with them are summarized as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Programming Language - Python&lt;/li&gt;
&lt;li&gt;Backend - Django&lt;/li&gt;
&lt;li&gt;Frontend - Django (HTML/CSS and Bootstrap)&lt;/li&gt;
&lt;li&gt;Database - PostgreSQL&lt;/li&gt;
&lt;li&gt;Hosting - Heroku&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find the repository for this project on my &lt;a href="https://github.com/Wolemercy/url-shortener"&gt;GitHub&lt;/a&gt;. You can check out the application &lt;a href="https://weburlshortener.herokuapp.com/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Development &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Django uses the Model-View-Template (MVT) pattern which is only slightly different from the general  Model-View-Controller (MVC) pattern because Django takes care of the Controller aspect. The Models, Views and Templates are essentially the building blocks of the project as they define how your app functions and interacts with the user.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Model
&lt;/h3&gt;

&lt;p&gt;The Django model provides an Object-relational Mapping (ORM) to the database. The models you define are mapped to tables in your database and they can all be connected. This &lt;a href="https://weburlshortener.herokuapp.com/"&gt;&lt;strong&gt;URL Shortener App&lt;/strong&gt;&lt;/a&gt; uses a model called &lt;code&gt;Shortener&lt;/code&gt;. Its fields are as seen in the snippet below. The save method is called to update the database with the shortened URL associated with the user's original URL.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  The Utility Function
&lt;/h3&gt;

&lt;p&gt;An utility function is used to generate the shortened URL as seen below. It checks if the created URL is unique  and only returns the generated code once that condition has been satisfied.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  The Form
&lt;/h3&gt;

&lt;p&gt;Forms are the receptacles of a user's input and they define the actions and methods (POST, GET) that get sent to the server. The &lt;code&gt;Form&lt;/code&gt; class is what handles forms in Django. It accepts specifics such as form fields, layouts, valid values, and so forth. More on that can be read &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Forms"&gt;here&lt;/a&gt;. Forms can be inherited from Models and that's the road more travelled. It was also the road I took.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Views
&lt;/h3&gt;

&lt;p&gt;The Views in Django are what take a user's web request and returns a response. Two basic view functions were used; one received the user's original URL and returned the shortened link while the other was responsible for redirecting the shortened link to the destination of the original URL.&lt;/p&gt;

&lt;p&gt;In defining the views, I also -&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;defined the logic that monitors the number of times the shortened link has been followed&lt;/li&gt;
&lt;li&gt;ensured that shortened links were only created if the user's URL wasn't currently existing in the database. If a record of the URL existed, the shortened URL associated with that record will simply be returned.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Templates
&lt;/h3&gt;

&lt;p&gt;These are files that define the structure of the HTML pages associated with the rendered views. Two templates were used—the base template and the home template. The former defines the general boilerplate  html code to be inherited by other more specific templates like the home template. The templates were written in HTML and the Django Template Language. The former reprised its role as the standard markup language for web pages while the latter made it possible to extend templates, insert conditionals, and call URLs associated with the application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tests
&lt;/h3&gt;

&lt;p&gt;This was my first experience writing tests for an application. Thankfully, the Django documentation proved really helpful. You can learn more about Django tests &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Testing"&gt;here&lt;/a&gt; and &lt;a href="https://docs.djangoproject.com/en/3.2/topics/testing/"&gt;here&lt;/a&gt;. I wrote tests for  the forms, models, and views. Below is a snippet of the unit tests written for the forms.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Deployment &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://weburlshortener.herokuapp.com/"&gt;&lt;strong&gt;URL Shortener App&lt;/strong&gt;&lt;/a&gt; was deployed using Heroku's free tier cloud service. It was a bit tricky but all I needed to do was follow the documentation as seen &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Deployment"&gt;here&lt;/a&gt;, and it was fine in the end. Heroku is well integrated with git so deploying and even redeploying after making some changes is not so complex.&lt;/p&gt;

&lt;p&gt;Furthermore, by default, Django makes use of an sqlite database which Heroku does not directly support. There are a few workarounds to that solves that problem but I ended up using a PostgreSQL database even in my local development environment. I could have done without that, yes. However, I wanted to learn how to incorporate a different database into an application and it was interesting doing exactly that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Opportunities for Improvement
&lt;/h3&gt;

&lt;p&gt;For the next iteration of this project, I intend to add a couple of functionalities including (and probably beyond):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;showing users the links they've created&lt;/li&gt;
&lt;li&gt;allowing users delete their created links&lt;/li&gt;
&lt;li&gt;dockerizing the application&lt;/li&gt;
&lt;li&gt;automating the tests&lt;/li&gt;
&lt;li&gt;making the UI a bit better &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Lessons &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I have categorized the critical things I learnt and the "big" challenges I faced into two; code-related and non-code-related.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code-related Lessons
&lt;/h3&gt;

&lt;p&gt;These lessons specifically have to do with new approaches to solving problems I discovered (I'm not Christopher Columbus, I know) in the course of this project. Some, you may already know, but are, to me, worthy of note.&lt;/p&gt;

&lt;h3&gt;
  
  
  Windows Terminal is the Truth
&lt;/h3&gt;

&lt;p&gt;I use a Windows environment and for a long time, Git Bash was sufficient to fulfill my command-line needs. In deploying the application to Heroku, however, I struggled with adding a SECRET_KEY to my application environment. It turned out that the ampersand (&amp;amp;) character which was part of my SECRET_KEY  was a  reserved character and it was not getting parsed as intended. I was stuck for a few hours trying to find a way around it and I tried different solutions as seen on the web to no avail. Single quotes, double quotes, backslashes, etc. Nothing worked.&lt;/p&gt;

&lt;p&gt;Then I decided to change my command-line environment from Git Bash to Windows Terminal and that did the trick. Using a PowerShell profile in Windows Terminal, I only had to wrap the ampersand character—and the close-parenthesis character,")"—in double quotes and the entire string in single quotes to get it to work. Honestly, I'm not quite sure why I stayed away from Windows Terminal for so long but I'll be using it here on out. It's customizable; it can be integrated with CMD, PowerShell and Linux environments; it supports "Ctrl + C" and "Ctrl + V" as the default copy and paste commands unlike Git Bash; and it also looks nice. &lt;/p&gt;

&lt;h3&gt;
  
  
  Python Decouple for Environment Variables
&lt;/h3&gt;

&lt;p&gt;In the past, I've always approached accessing environment variables by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;creating a JSON file and storing the environment variables therein&lt;/li&gt;
&lt;li&gt;writing a a few lines of code in my settings.py file to read the JSON file&lt;/li&gt;
&lt;li&gt;accessing each variable in the JSON file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, in the course of this project, I picked up on using the Python Decouple library to access my secret keys. Once installed with pip, I only needed to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create an &lt;code&gt;.env&lt;/code&gt; file and store the environment variables&lt;/li&gt;
&lt;li&gt;import the config object from decouple in my settings.py file&lt;/li&gt;
&lt;li&gt;access each variable in the &lt;code&gt;.env&lt;/code&gt; file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In both methods, it is necessary to include the JSON and &lt;code&gt;.env&lt;/code&gt; files in a &lt;code&gt;gitignore&lt;/code&gt; file. However, the latter  is a lot quicker to implement than the former as it saves me a couple of lines, and going forward, it is definitely the way to go.&lt;/p&gt;

&lt;h3&gt;
  
  
  Non-Code-related Lessons
&lt;/h3&gt;

&lt;p&gt;These lessons aren't particularly linked to code but they were important things to note.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sometimes, it is okay to fail a test
&lt;/h3&gt;

&lt;p&gt;If you'd told me in high school that I'd one day look forward to failing a test, I would have punched you in the face to snap you out of that illusion. Okay, maybe that's going a bit too far but you catch the drift. Being optimistic and more so, delighted about a failed test is not exactly a "natural" emotional state. &lt;/p&gt;

&lt;p&gt;However, while writing tests for this &lt;a href="https://weburlshortener.herokuapp.com/"&gt;&lt;strong&gt;URL Shortener App&lt;/strong&gt;&lt;/a&gt;, some were specifically designed to fail. The successes of these tests were hinged on their failure. The tests had to fail for them to pass, for lack of a less ironic expression. This was for me, a rather poignant reminder that failure is not inherently a bad thing. For all the stigma and unenviable disrepute it continues to garner, failure, sometimes, is okay.&lt;/p&gt;

&lt;h3&gt;
  
  
  Front-end isn't bread and butter
&lt;/h3&gt;

&lt;p&gt;"It's just styling". Eh, no it's not! At least not for me. Giving the &lt;a href="https://weburlshortener.herokuapp.com/"&gt;&lt;strong&gt;URL Shortener App&lt;/strong&gt;&lt;/a&gt; a good interface wasn't the easiest of things for me. From the layout and the elements to the fonts and colors, it was a bit difficult. I refer more to deciding on what to do rather than the implementation. For instance, choosing the color scheme for the site was  a bit frustrating. If you think my final decision isn't so good, wait till you see what my many iterations looked like. For this bit, I'd appreciate any resource or tips that could help improve the choice of colors and page styling in general.&lt;/p&gt;

&lt;h3&gt;
  
  
  I have a thing for this thing called &lt;code&gt;Code&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;I thoroughly enjoyed building this App. I'm not exactly a code newbie but I'm green to Software Engineering, and it is, for  me, an exciting frontier. I look forward to building even better products, and learning from and collaborating with other Engineers.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

&lt;p&gt;Let me know what you think about this &lt;a href="https://weburlshortener.herokuapp.com/"&gt;&lt;strong&gt;URL Shortener App&lt;/strong&gt;&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Also connect with me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LinkedIn: &lt;a href="https://www.linkedin.com/in/wolemercy"&gt;Wolemercy&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Twitter:  &lt;a href="https://twitter.com/wolemercy"&gt;Wolemercy&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>django</category>
      <category>webdev</category>
      <category>heroku</category>
    </item>
  </channel>
</rss>
