<?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: nwdunlap17</title>
    <description>The latest articles on DEV Community by nwdunlap17 (@nwdunlap17).</description>
    <link>https://dev.to/nwdunlap17</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%2F218331%2Ffc002269-5376-403d-a19a-cc96e2c679d5.png</url>
      <title>DEV Community: nwdunlap17</title>
      <link>https://dev.to/nwdunlap17</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nwdunlap17"/>
    <language>en</language>
    <item>
      <title>Deploying your first AWS application
</title>
      <dc:creator>nwdunlap17</dc:creator>
      <pubDate>Sat, 04 Jan 2020 09:50:27 +0000</pubDate>
      <link>https://dev.to/nwdunlap17/deploying-your-first-aws-application-2cj5</link>
      <guid>https://dev.to/nwdunlap17/deploying-your-first-aws-application-2cj5</guid>
      <description>&lt;p&gt;My &lt;a href="https://dev.to/nwdunlap17/what-is-aws-4pm5"&gt;previous post&lt;/a&gt; focused on the key motivations behind using AWS, as well as overviews of the most used services. This post will cover how to get a simple application up and running on the cloud.&lt;/p&gt;

&lt;p&gt;The very first thing to do is to &lt;a href="https://aws.amazon.com/"&gt;make an AWS account&lt;/a&gt;. This will require you to input a credit card, but don’t worry, there’s no fee. AWS only charges you for the services you use, and most of those services offer a Free Tier, even those that don’t will have an option that is measured in pennies per million users or pennies per terabyte. So just make sure your test application isn’t something ridiculous like uploading your entire movie collection.&lt;/p&gt;

&lt;p&gt;Now that you have an account, let’s go over the ways that you can access and manage your AWS account and projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  The AWS console and you
&lt;/h3&gt;

&lt;p&gt;After creating your account, you will be forwarded to the AWS web console. This serves as a ‘home screen’ for your account, and allows you to easily manage services, create or delete instances, and set up automated responses for your application. The AWS console is easily the most intuitive way to set up and manage your services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--H5MKATUm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/64ofd872r6zzlbec6sjd.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--H5MKATUm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/64ofd872r6zzlbec6sjd.PNG" alt="The Web AWS management Console"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The AWS command line interface
&lt;/h3&gt;

&lt;p&gt;The AWS CLI is a powerful tool that allows you to manage every aspect of every AWS service from your local machine. You can download the packages for the CLI &lt;a href="https://aws.amazon.com/cli/"&gt;here&lt;/a&gt;. Windows users can just download and run the installer, Mac and Linux users (or users running a Linux CLI on Windows) will install using pip.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ pip install awscli
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you don’t have pip installed, the page provided has a bit more instruction on how to install it, as well as how to handle some potential issues. Verify that the cli is properly installed by checking its version.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws –version
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If this fails and the installation otherwise appeared to work, try restarting your computer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up access
&lt;/h3&gt;

&lt;p&gt;Before we can get to our app, we need to be able to communicate between our local machine and the partitions we’ll create using our AWS account. In the upper right of the screen, click on your name to show a dropdown, then click &lt;strong&gt;My Security Credentials&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iTkAaul6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/vz6c4rw524p9bjvina2v.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iTkAaul6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/vz6c4rw524p9bjvina2v.PNG" alt="The drop down showing security credentails"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You’ll get a pop up warning you that your account credentials provide unlimited access to all of your AWS resources, and recommending that you use an IAM account instead. If we were doing something important, then we would want to take that advice. Using an account with unlimited permissions is dangerous, you might accidentally delete something or divert a resource from one project to another. Ideally, we should create a separate IAM identity, which would have its permissions restricted such that we couldn’t damage anything. &lt;/p&gt;

&lt;p&gt;But for now, we have nothing to lose. Close the window and click on the &lt;strong&gt;Access Keys (access key ID and secret access key)&lt;/strong&gt; tab. Then click &lt;strong&gt;Create New Access Key&lt;/strong&gt;. This will generate a new key pair, which you should download.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--50eNj29o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/4qprfd6huxlb316k9o85.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--50eNj29o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/4qprfd6huxlb316k9o85.PNG" alt="A successfully created access key"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open your command line and run the command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws configure
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You will be prompted to input the ID and secret from the Access Key you just downloaded. You will then be asked for your Default region name, go back to your browser, click on the logo to bring you back to the AWS console home, and click on the location next to your user name. You’ll see a list of locations a names, pick whichever location is closes to you and enter its associated name. MY closest location was Oregon, so I entered &lt;em&gt;us-west-2&lt;/em&gt;. Finally, choose your output format, this will be the format of responses given by the CLI. I recommend &lt;em&gt;json&lt;/em&gt;, it’s much more readable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AQl7Lb48--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/6y7lal84j258lvojw1ys.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AQl7Lb48--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/6y7lal84j258lvojw1ys.PNG" alt="A CLI terminal showing aws configure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you have completed this, you should try the command below. If you have successfully completed set up, you should receive a see all of the Elastic Cloud Compute instances you have created so far. Since we’ve just started, this should be an empty array. If you receive an error message instead, double check that aws cli is installed, or try &lt;em&gt;aws configure&lt;/em&gt; again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws ec2 describe-instances
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Starting with Virtual Private Clouds
&lt;/h3&gt;

&lt;p&gt;I mentioned the power of VPCs in the previous post. In short, it’s a partition which will hold all the subnets and instances used in your application. It will also handle all of the routing to and from your application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--n-tsnxKI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/y4qse9w5bimcyequ7izv.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--n-tsnxKI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/y4qse9w5bimcyequ7izv.PNG" alt="The VPC Dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go to your AWS console home and search for ‘VPC’. Click the &lt;strong&gt;Launch VPC wizard&lt;/strong&gt; button. This will bring you to a screen where you can select the starting architecture for your VPC. Go ahead and leave the default option: Single Public Subnet.&lt;/p&gt;

&lt;p&gt;This will take you to the IP settings page for your VPC. Since we selected Single Public Subnet, we have the option of choosing the range of IPs for the subnet within the VPC. The values in this range are arbitrary, so long as they are within the bounds of the VPC. Select any &lt;strong&gt;Availability Zone&lt;/strong&gt; for your subnet. Don’t forget to give both your VPC and subnet a name. Now just hit &lt;strong&gt;Create VPC&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AobYxO29--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/snjcxllqu0qqgwkc1kmg.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AobYxO29--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/snjcxllqu0qqgwkc1kmg.PNG" alt="Step 2: setting up VPC and subnet"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Now you’ve created your VPC, but it still doesn’t have any routing behavior. We want to allow users to come in and view our app. Click &lt;strong&gt;OK&lt;/strong&gt; to continue back to the &lt;em&gt;Your VPCs&lt;/em&gt; tab, which should now list your newly created VPC. Click the link in the ‘Main Route Table’ column, it should be a string of characters beginning ‘rtb-‘. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1GXzCZtj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/npkqmuqwueu1yjrmapny.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1GXzCZtj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/npkqmuqwueu1yjrmapny.PNG" alt="The VPC table"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will take you to the route table. At the bottom of the screen, click the &lt;strong&gt;routes&lt;/strong&gt; tab and the &lt;strong&gt;Edit routes&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--n9zUu0e2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/zxkth0nf3m64e3mw3naf.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--n9zUu0e2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/zxkth0nf3m64e3mw3naf.PNG" alt="Modifying the routes in the Routing Table"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add a new route with the Destination ‘0.0.0.0/0’, this is effectively a wildcard, and will handle incoming requests from any IP. Click on the Target drop down, since we want to make this publicly available, select &lt;em&gt;Internet Gateway&lt;/em&gt;. You will see an identifies beginning with ‘igw-‘, this is the gateway that was created with the VPC.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating your EC2 Instance
&lt;/h3&gt;

&lt;p&gt;EC2 is the core building block of most AWS applications. It is a virtual machine which you can launch and use to host your application. From the home page of the AWS console, do a search for EC2 to arrive at its dashboard. Click the &lt;strong&gt;Launch instance&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;Your first decision will be to choose an Amazon Machine Image (AMI). These are a combination of the OS and pre-installed software for your virtual machine. Note that not all of these images are free tier eligible, so be careful with which one you select. I’m going to be posting a Ruby-on-Rails application, so I select “Amazon Linux AMI”. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aNXghcjS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/dqq7nchzhihjbaxa86fm.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aNXghcjS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/dqq7nchzhihjbaxa86fm.PNG" alt="Selecting the AMI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 2 is easy, because only one option is free tier eligible! It’s selected by default, so just click &lt;strong&gt;Next&lt;/strong&gt; in the lower right.&lt;/p&gt;

&lt;p&gt;In step 3, ensure that your Network is set to your VPC, and then your Subnet is set appropriately. Then hit &lt;strong&gt;Next&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OzoC6yeK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ahp2w8h8pl8rmjt6c52w.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OzoC6yeK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ahp2w8h8pl8rmjt6c52w.PNG" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 4 is storage. You can set the size of your instance in GiB. The default is 8, but you can scale that up to 30 and still stay in the free tier.&lt;/p&gt;

&lt;p&gt;Step 5 is tags. At the very least, you should give your instance a name so its easier to identify later. Click &lt;strong&gt;Add tag&lt;/strong&gt;, put ‘Name’ in the Key field, and whatever you want to call the instance in the Value field.&lt;/p&gt;

&lt;p&gt;Finally we reach step 6. Security groups control what has access to your app. You can create a new security group here, or assign it to an existing one. When creating a default security group, your app is only accessible by anyone that has the SSH key (which we’ll create in a second). Since I want my application to be public, I added a new rule which allows connections from anywhere on port 3000.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ueS5snLn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0xuk0b9dtsigrzuw4v6a.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ueS5snLn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0xuk0b9dtsigrzuw4v6a.PNG" alt="Configuring Instance Details"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go ahead and hit Next and Launch. You’ll see a pop up which asks you to determine the key pair you’d like to use for your instance. Select ‘Create a new key pair’ and give it a name. Then click &lt;strong&gt;Download Key Pair&lt;/strong&gt; and save it somewhere safe. Then click &lt;strong&gt;Launch Instance&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting an Elastic IP
&lt;/h3&gt;

&lt;p&gt;Elastic IP addresses are public addresses can be reassigned to different targets. This allows you to pull off some pretty useful tricks, such as seamlessly switching between an older and newer version of your application. For now, however, we’re just going to use it to connect our application to the public internet. I know I’ve said ‘connect our application to the internet’ a lot already, but so far we’ve only set up the permissions and routes that will allow users from our to access our instance. We still need to build the last bit of that bridge and allow users to find our instance in the first place.&lt;/p&gt;

&lt;p&gt;You’ll find the &lt;em&gt;Elastic IPs&lt;/em&gt; link on the left side of the EC2 dashboard. You may have to scroll down to see it. Simply click &lt;strong&gt;Allocate Elastic IP address&lt;/strong&gt;. You’ll have the option to use an address that you own, or one of Amazons. Since I don’t own my own IP address, I used the latter.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--f3WITf6h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/qiqy6lfpxnxnch4pp89e.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f3WITf6h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/qiqy6lfpxnxnch4pp89e.PNG" alt="Configuring Security Group"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the Elastic IP is created. Select it and click the &lt;em&gt;Actions&lt;/em&gt; tab at the top of the EC2 dashboard, and then &lt;em&gt;Associate IP address&lt;/em&gt;. You’ll see a simple menu where you can select the instance you want to associate, instances are identified by a long string of characters beginning with ‘i-‘. Fortunately, if you added a name tag for the instance earlier, that will appear as well. Once you’ve selected the instance, click the Private IP address field, which should only give you the one option, and hit &lt;strong&gt;Associate&lt;/strong&gt;.&lt;br&gt;
You’ll now have an IPv4 address associated with your instance. Copy it, because we’ll be using it in the next step.&lt;/p&gt;
&lt;h3&gt;
  
  
  Sending your files to your Instance
&lt;/h3&gt;

&lt;p&gt;Remember your key that you downloaded when you created your instance? It was downloaded as a .pem file. You’ll be using scp to send your files up to your instance. If you’re using Windows, you’ll need to first convert the .pem to a .ppk and use pscp instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Extra Step for Windows Users&lt;/strong&gt;: First, download &lt;a href="https://www.puttygen.com/"&gt;PuTTYgen&lt;/a&gt;. Once its installed, start it up and click &lt;em&gt;Load&lt;/em&gt;, select the .pem file (you may need to switch the file type in the browser to ‘All files’). You should get a message that the conversion was successful. Then select &lt;em&gt;Save private key&lt;/em&gt; to save your .ppk file.&lt;/p&gt;

&lt;p&gt;In whichever CLI you prefer, use the following command to send your files. (Remember, if you are on a Windows machine, you will use ‘pscp’ instead of ‘scp’.) Anything included in &amp;lt;&amp;gt; brackets should be replaced with the appropriate value, and don’t include the brackets. 'Chosen address' is whatever file path you want your file to be placed in. You can even leave it blank if you just want to deposit your file in the instance’s home directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ scp -r -i &amp;lt;path-to-key-file&amp;gt; &amp;lt;file-to-transfer&amp;gt; ec2-user@&amp;lt;instance ip&amp;gt;:/home/ec2-user/&amp;lt;chosen address&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;My version of the command was&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ pscp -r -i ./IronDocAWS.ppk ./IronDocs ec2-user@44.231.36.250:/home/ec2-user/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Accessing your Instance
&lt;/h3&gt;

&lt;p&gt;Finally, let’s dig into our instance! If you’re using Linux or MacOS, you’ll be using the ‘ssh’ command to log into the instance. If you’re a Windows user, you can access with PuTTY, or you can just use the Ubuntu command line which is compatible with Windows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh -i &amp;lt;path to pem file&amp;gt; ec2-user@&amp;lt;ip of instance&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you get an error that says your permissions are “too open”, you need to secure your file. Run the command below, which will set the permissions of your file such that only you are able to read it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ chmod 400 &amp;lt;path to pem file&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If all has gone well, you should be in! You can now install the necessary software to run your application. For me, this was installing rails along with all of my gems. And voila, you are now being hosted by the Amazon cloud!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IPdWTi1p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/82ob11o3eunihrdenybz.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IPdWTi1p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/82ob11o3eunihrdenybz.PNG" alt="Terminal successfully accessing instance"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are using nodejs for your server's front-end, you can just run 'npm start' and view your project by visiting :3000 in your browser.&lt;/p&gt;

&lt;p&gt;If you're using a rails front end, you'll have to remember to deploy to an IP other than localhost. Use 'rails s -b 0.0.0.0', otherwise you'll get a 'failed to load' error when you try to connect.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>beginners</category>
    </item>
    <item>
      <title>What is AWS?</title>
      <dc:creator>nwdunlap17</dc:creator>
      <pubDate>Sat, 28 Dec 2019 08:58:49 +0000</pubDate>
      <link>https://dev.to/nwdunlap17/what-is-aws-4pm5</link>
      <guid>https://dev.to/nwdunlap17/what-is-aws-4pm5</guid>
      <description>&lt;p&gt;If you’re looking for work as a software developer, it won’t be long until you run into the term ‘AWS’, or ‘Amazon Web Services’. It shows up in developer job descriptions across every industry. If you’re anything like me, you’d be very curious as to what AWS actually does. &lt;/p&gt;

&lt;p&gt;Here’s the very short version: AWS lets users run their applications on Amazon’s hardware. &lt;/p&gt;

&lt;p&gt;Here’s the longer version: Amazon Web Services is a massive set of services that handle hosting, managing, supporting, and protecting your applications. Below is a screenshot of the AWS console which shows only about a quarter of the offered services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OdWdYEWH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/p7jsd1jbtc4ysf8q7vwb.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OdWdYEWH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/p7jsd1jbtc4ysf8q7vwb.PNG" alt="A screen with about 40 different AWS tools, there are many more"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clearly, that’s too many to explore in a reasonable time. And I would be lying if I said I knew what half of them do, so I’ll just be going over the basics of AWS: why it’s important and which services are the most fundamental.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use AWS?
&lt;/h2&gt;

&lt;p&gt;So what makes AWS so useful? Why do so many companies choose to let Amazon handle their hardware needs?  &lt;/p&gt;

&lt;p&gt;Simple, hardware is expensive. Buying servers is expensive and limited. First, you need a place to put it, which means if you want your app to have low latency in both California and Taiwan, you’d better be willing to pay for two pieces of real estate. Second, you need to be very accurate in judging the size of your user base. Too few servers and you won’t be able to handle the excess requests, too many and you’ve wasted money on idle servers. Finally, servers wear down and need to be replaced over time.&lt;/p&gt;

&lt;p&gt;Fortunately, Amazon is a globe-spanning, multi-billion dollar corporation. They already have large server farms in Oregon, Hong Kong, and London. They’re willing to lease all of that computing power, and the best part is that they only charge for the resources that you’re using. If your app is having a slow traffic day, you can save money by reducing the number of instances you’re running. If your app soars in popularity, it can immediately request additional resources so that it can handle the load.&lt;/p&gt;

&lt;p&gt;This adaptability and low entry cost has made AWS incredibly popular with companies and start-ups, and has lowered the barrier to entry for many applications. Airbnb, IMDb, and Pintrest are all hosted through AWS. Even some larger companies like Netflix and McDonalds have decided its cheaper to use AWS rather than in-house options.&lt;/p&gt;

&lt;p&gt;Speaking of low barrier to entry, you can make an AWS account right now, and start their 1 year free-tier trial. So there is no cost to creating an account and learning how to use this powerful tool. Let’s look at some of the services you should try first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Virtual Private Cloud
&lt;/h2&gt;

&lt;p&gt;The first thing you’ll need to do when working with AWS is to create a virtual space for your projects to exist. Virtual Private Cloud, or VPC, allows you to isolate your applications and resources from the outside world. A VPC can hold multiple &lt;strong&gt;subnets&lt;/strong&gt;, which manage how their contents can be accessed. &lt;/p&gt;

&lt;p&gt;Breaking up VPCs into subnets gives some very powerful options. You might have two subnets in a VPC, one which is accessible to the outside world, and one which is accessible only by its sibling. This allows users to create very secure infrastructures for their applications. Another option is to create identical subnets and run them in different locations, this allows for redundancy should one of the locations fail. Another option is to use a &lt;strong&gt;Load-balancer&lt;/strong&gt; to direct users to the least used subnet of set, ideally keeping latency and load manageable.&lt;/p&gt;

&lt;p&gt;VPCs and subnets are necessary to host the real meat and potatoes of your app: EC2 instances.&lt;/p&gt;

&lt;h2&gt;
  
  
  Elastic Cloud Compute
&lt;/h2&gt;

&lt;p&gt;The foundation for most AWS applications is handled by the Elastic Cloud Compute service, or ‘EC2’ for short. EC2 allows you to set up virtual servers, called &lt;strong&gt;instances&lt;/strong&gt;, in the Amazon cloud. You can do anything with an instance that you could with a computer: run applications, connect with other machines, or even act as desktops.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1zWqhT6t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/p9wm4cezq6boglo6bsab.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1zWqhT6t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/p9wm4cezq6boglo6bsab.PNG" alt="List of AMIs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;EC2 supports many operating systems, so you can create your EC2 instance with whatever OS best fits your needs at the time. Each instance is launched with an Amazon Machine Image, which defines the OS, as well as which software is preinstalled. You can start up a basic AMI that just runs Linux or Windows, or you can choose an image which has been optimized for a specific task, like Amazon Deep Learning Image.&lt;/p&gt;

&lt;p&gt;You can also define your own images. After installing your application and its dependencies in one instance, you can save that instance as an image. This allows you to create new instances that are ready to run your application immediately. This allows you to easily scale your application up or down to accommodate a changing number of users. You can even use some of the other AWS features to automate this process!&lt;/p&gt;

&lt;h2&gt;
  
  
  Simple Storage Service
&lt;/h2&gt;

&lt;p&gt;Simple Storage Service, or S3, is the primary service used to store files on AWS. Much like instances for EC2, S3 has its own building blocks called &lt;strong&gt;buckets&lt;/strong&gt; and &lt;strong&gt;objects&lt;/strong&gt;. The relationship between buckets and objects is pretty self-explanatory. An object can be any type of file, and has attached meta-data which holds file type and last-modified date. Objects are stored in buckets. Each bucket has a DNS attached to it, so you can access the contents of your bucket through a URL. You can control the access rights to a bucket, which is by default only accessible to its creator. You can make buckets visible and editable to other AWS accounts, or the public at large.&lt;/p&gt;

&lt;p&gt;One thing to note for aspiring AWS users is that S3 does not technically have a ‘free tier’ like many of the other services, so you will be paying to use it. Don’t worry too much about it though, because the prices are measured in fractions of pennies per Terabyte per month. If I leave my 20 GB of content alone in my bucket forever, I’ll owe Amazon my the first penny sometime in the 24th century.&lt;/p&gt;

&lt;p&gt;Finally, S3 works best for static files such as documents, media, or program files. More dynamic files, such as frequently accessed databases, are better served by some of the other AWS services.&lt;/p&gt;

&lt;h2&gt;
  
  
  Relational Database Service
&lt;/h2&gt;

&lt;p&gt;RDS is AWS’s tool for SQL databases. The building block of RDS is called an &lt;strong&gt;instance&lt;/strong&gt; because it is really just a specialized EC2 instance. RDS instances have additional features for better reliability and data protection. Backups of RDS databases are performed daily, and can be held for up to a month depending on your settings. This allows you to retrieve your data should it become lost or corrupted.&lt;/p&gt;

&lt;p&gt;Earlier, when I was describing subnets, I mentioned that you could have multiple identical subnets in case one fails. The same idea is present in RDS through &lt;strong&gt;Multi-AZ Deployment&lt;/strong&gt;, where multiple copies of a database are kept in &lt;br&gt;
separate locations. Should one location fail, requests for the database are automatically routed to the surviving databases.&lt;/p&gt;

&lt;p&gt;Finally, RDS can produce &lt;em&gt;Read-Replicas&lt;/em&gt; of a database. These replicas are essentially copies of a database that are updated when the RDS instance has spare processing power. RDS will never pull information from these replicas, even during the event of a location failure. They provide a way for the database to be read without impacting customer-facing resources.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Introduction to Neural Networks with Brain.js</title>
      <dc:creator>nwdunlap17</dc:creator>
      <pubDate>Tue, 08 Oct 2019 04:26:35 +0000</pubDate>
      <link>https://dev.to/nwdunlap17/introduction-to-neural-networks-with-brain-js-4i80</link>
      <guid>https://dev.to/nwdunlap17/introduction-to-neural-networks-with-brain-js-4i80</guid>
      <description>&lt;h2&gt;
  
  
  What is a Neural Network
&lt;/h2&gt;

&lt;p&gt;Neural Networks are incredibly useful computing structures that allow computers to process complex inputs and learn how to classify them. The functionality of a neural network comes from its structure, which is based off the patterns found in the brain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4XiAvCCB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1200/1%2AYgJ6SYO7byjfCmt5uV0PmA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4XiAvCCB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1200/1%2AYgJ6SYO7byjfCmt5uV0PmA.png" alt="A neural network"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice that the network is divided into three distinct &lt;strong&gt;Layers&lt;/strong&gt;. When a neural network is in use, it activates the layers from left to right, leading from input to output. It is also possible for there to be multiple hidden layers, but we’ll tackle that later.&lt;br&gt;
Each circle in the above diagram is a &lt;strong&gt;Neuron&lt;/strong&gt;. Each neuron’s job is to measure a specific variable, and the higher the layer the neuron is in, the more information that variable has. An input neuron might measure the brightness of a single pixel, neurons in the middle may describe individual elements of a picture, and an output neuron would describe the whole picture. This value is a number that fits in a specific range (like between 0 and 1), which is called the neuron’s &lt;em&gt;activation&lt;/em&gt;. Neurons also have a second value called a &lt;strong&gt;bias&lt;/strong&gt;, which changes the default value of the neuron away from 0.5.&lt;br&gt;
Each neuron in a layer has a connection to every neuron in the next layer. Each of these connections has a &lt;strong&gt;weight&lt;/strong&gt;, which is a value that represents how the two neurons relate to each other. A highly positive weight means that the first neuron makes the second more likely to activate, where a high negative weight means the first prevents the second from activating. A weight of 0 means the first neuron has absolutely no effect on the second. &lt;/p&gt;

&lt;p&gt;When input data is fed into a neural network, it creates a set of activation values in the first layer. Every connection in this layer then ‘fires off’ in sequence. When a connection fires, it multiplies the activation of the left neuron by the weight of the connection, then adds that to a running total for the right neuron along with the bias. At the end of this process, every neuron in the left layer has contributed to every neuron in the right layer.&lt;br&gt;
Because the resulting number can be anywhere on the number line, and activations must be between 0 and 1, we need to use a function to convert the result into the appropriate range. There are many functions that work for this purpose, such as Sigmoid. Once an activation value has been generated for every neuron in the layer, the process repeats until the output layer is reached.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3cgNtxd8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AXu7B5y9gp0iL5ooBj7LtWw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3cgNtxd8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AXu7B5y9gp0iL5ooBj7LtWw.png" alt="The Sigmoid function"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example, in the situation below we have three nodes in the first row contributing to one node in the next. The topmost node contribute 4.0 * 0.5 = 2.0, the middle node 0.5, and the bottom node -1, which sum to 1.5. The affected node also has a bias of -2, so the total is -0.5. Plugging this value into the Sigmoid function results in a 0.378 activation value.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cNRHIz0i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/nc086h9cewimnnitlt4w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cNRHIz0i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/nc086h9cewimnnitlt4w.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Okay, so we have some math that lets us shuffle some numbers around, but we can do that with any function. Why do we need to have all this business with neurons and connections and layers?&lt;/p&gt;
&lt;h2&gt;
  
  
  Learning
&lt;/h2&gt;

&lt;p&gt;There a lot of unknowns in the neural network, every neuron in the network has a bias, and every connection between neurons has a weight. All these values can be tweaked and modified to produce neural networks that will have different behaviors. Of course, most of these possible combinations will give us entirely useless answers. How do we narrow down from the infinite possible combination to one of the few usable sets?&lt;br&gt;
First, we need to define some way to tell how well any given configuration of the neural network is doing. This is done by creating a &lt;strong&gt;cost function&lt;/strong&gt;, which is usually the sum of the squares of the difference between the expected and actual answers. When the cost function is high, the network is doing poorly. But when the cost function is near 0, the network is doing very well. Just knowing how well a network deals with a single sample isn’t very useful, so this is where large data sets come in. The effectiveness of a set of weights and biases is determined by running hundreds if not thousands of samples through the neural net.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Da5vkmbq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bing.com/th%3Fid%3DOIP.FTAO32ReL-z6AelZ0ajlMgHaEr%26pid%3DApi%26rs%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Da5vkmbq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bing.com/th%3Fid%3DOIP.FTAO32ReL-z6AelZ0ajlMgHaEr%26pid%3DApi%26rs%3D1" alt="3d plot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we were to plot our cost function for every possible value of the parameters, then we would have a plot similar to (but immensely more complicated than) the one above. Because this is the cost function, the lowest points on the plot represent the most accurate sets of parameters. We can therefore find the local minima of the function by using steepest descent. Steepest decent involves finding the highest slope of the nearby section of plot, and then moving away from that rise. This involves a lot of &lt;a href="https://www.math.usm.edu/lambers/mat419/lecture10.pdf"&gt;calculus I don’t have time to replicate here&lt;/a&gt;, and is incredibly slow.&lt;/p&gt;
&lt;h3&gt;
  
  
  Learning Faster with Backpropagation
&lt;/h3&gt;

&lt;p&gt;Backpropagation offers a much faster way to approximate steepest descent. The key idea behind is essentially: feed a sample into the neural network, find where the answer deviates from the expected value, find the smallest tweaks you can do to get the expected answer.&lt;br&gt;
This process works due to the wide branching structure of neural networks. Because neurons are fed through so many different paths, and each path has different weight associated with it, it’s possible to find values that are order of magnitude more influential on the values you care about than others. Following this process leads to a list of changes to make to existing weight and bias values. Applying just these changes will lead to overtraining your data set, so you need to get a good average before making any changes. You should shuffle your data set so that you get a random assortment of samples, generating lists of changes for each one. After averaging a few hundred of these lists together, then you can enact changes to the network. While each individual nudge resulting from this won’t be in the steepest descent, the average will eventually drag the cost function to a local minimum.&lt;/p&gt;
&lt;h2&gt;
  
  
  Enough with the Theory Already!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/BrainJS/brain.js"&gt;Brain&lt;/a&gt; is a javascript library made for easy and high-level neural networking. Brain handles almost all of the set up for you, allowing you to worry only about high level decisions. &lt;br&gt;
&lt;strong&gt;Scaling Function&lt;/strong&gt;: Sets the function for determining the activation value of neurons.&lt;br&gt;
&lt;strong&gt;Number of Hidden Layers&lt;/strong&gt;: The number of additional layers between the Input and Output layers. There is almost no reason to use more than two layers for any project. Increasing the number of layers massively increases computation time.&lt;br&gt;
&lt;strong&gt;Iterations&lt;/strong&gt;: The number of times the network is run through the training data before it stops.&lt;br&gt;
&lt;strong&gt;Learning Rate&lt;/strong&gt;: A global scalar for how much values can be tweaked. Too low, and it will take a very long time to converge to the answer. Too high, and you may miss a local minimum.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const network = new brain.NeuralNetwork({
    activation: ‘sigmoid’,  //Sets the function for activation
    hiddenLayers: [2],  //Sets the number of hidden layers
    iterations: 20000, //The number of runs before the neural net stops training
    learningRate: 0.4 //The multiplier for the backpropagation changes
}) 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The above parameters are passed into the NeuralNetwork class as an object. The network can then be trained using the .train method. This requires prepared training data. Sample data should be structured as an array of objects with input and output values. The input and output values should be an array of numbers, these correspond to the activation values of the neurons in the first and last layers of the network, respectively. Its important that the number of elements in the input and output arrays remain consistent (internally, they don’t have to be equal to each other) as this determines the number of nodes that will exist in the front and back layers of the network.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let trainingSample1 = {
    input: [ 5.3, 6 , 1 , -4 ]
    output: [ 0 , 1  ] 
}

let trainingSample2 = {
    input: [ 1 , -14 , 0.2 , 4.4 ]
    output: [ 1 , 1  ] 
} 
trainingData.push( trainingSample1 )
trainingData.push( trainingSample2 )

network.train(trainingData)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And now the network has done its level best to train itself under your chosen settings and samples. You can now use the .run command to examine the output for a given sample. And voila, your network will be able to make approximations based off of any given input. I’d say it’s like magic if you hadn’t just read 1000 words explaining how it works.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    let sample = [20, -3, -5, 13]
    let result = network.run(sample)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>javascript</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>What Features do I Keep? - Design Tips for Software, Board Games, and Knives</title>
      <dc:creator>nwdunlap17</dc:creator>
      <pubDate>Mon, 23 Sep 2019 23:35:58 +0000</pubDate>
      <link>https://dev.to/nwdunlap17/feature-creep-and-user-feedback-design-tips-for-games-software-and-knives-2h4g</link>
      <guid>https://dev.to/nwdunlap17/feature-creep-and-user-feedback-design-tips-for-games-software-and-knives-2h4g</guid>
      <description>&lt;h2&gt;
  
  
  The 'Everything' Machine
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;“Focusing is about saying 'No'.” -Steve Jobs&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We’ve all been there: you’re creating something, maybe it’s a project for school, or a flash game, or a fancy new kitchen appliance. As a designer, it’s your job to answer the question “What can my creation do?”.  And there’s a natural temptation among developers to answer that question with “Everything”. After all, more is better, right? &lt;/p&gt;

&lt;p&gt;That instinct is a trap. Variety sounds nice in theory, but in practice it can cause quite a few problems. For every feature added to a product, the other features need to be altered to accommodate. A tool might have to be reshaped, software might have overly general scope, and a marketing campaign might become diluted. Even if you avoid some of these pitfalls, the extra development time/complexity is going to manifest as increased price. As a result, it’s generally more efficient to make multiple focused products rather than one product that covers a wide range of features. &lt;/p&gt;

&lt;p&gt;Here’s a real-world example. Off the top of your head, what tool you would use to do the following tasks?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Insert a screw into IKEA furniture.&lt;/li&gt;
&lt;li&gt;Open a beer bottle.&lt;/li&gt;
&lt;li&gt;Cut a shape out of some construction paper.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’m guessing that your answers were a screwdriver, a bottle opener, and a pair of scissors. You could have answered ‘Swiss Army knife’ for every question, but it’s pretty clear why that wouldn’t be a good first choice. Each tool has to be shrunken down in order to cram into the knife with all the others. That makes it difficult to rotate the T-shaped screwdriver, get grip with the thin bottle opener, or cut quickly with the short scissors.&lt;/p&gt;

&lt;p&gt;The Swiss Army knife is actually an interesting example, because it gets a benefit in return for its compromises. Its small size and weight make it far more &lt;em&gt;portable&lt;/em&gt; than full sized tools. You would never use a Swiss Army knife if another tool was available, but because it fits in your pocket, it always gives you a serviceable option. In this way, it’s not competing with ‘proper’ tools, but targeting its very own niche!&lt;/p&gt;

&lt;p&gt;The traditional Swiss Army knife was designed with a certain amount of restraint, as versatile as they are, they usually have less than ten functions each. Let’s imagine what would happen if the manufacturers ran wild and added every feature they could think of. There are so many tools out there! What if they added pliers? A magnifying glass? A wrench? What about a saw? Sure, throw ‘em all in there! Pretty soon you’ll have something like this!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VFLOXxes--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://smhttp-ssl-53433-prd.nexcesscdn.net/media/catalog/product/cache/1/image/9df78eab33525d08d6e5fb8d27136e95/s/a/sa16795xavtx1000_1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VFLOXxes--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://smhttp-ssl-53433-prd.nexcesscdn.net/media/catalog/product/cache/1/image/9df78eab33525d08d6e5fb8d27136e95/s/a/sa16795xavtx1000_1.jpg" alt="A ridiculous Swiss Army Knife"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That monstrosity costs over &lt;em&gt;four hundred&lt;/em&gt; dollars. And many of those tools are unusable. A magnifying glass that small is pointless, and can you imagine anything you could cut with that tiny saw? Worse, it’s gotten so wide that it will hardly fit in a pocket anymore. At this point, any customer is better off just buying a tool belt.&lt;/p&gt;

&lt;p&gt;This thing is suffering from a bad case of &lt;em&gt;Feature Creep&lt;/em&gt;. Feature Creep is the tendency for designers to keep adding more and more features to a product, well past the point it stops making sense. In a physical product like the one above, it’s pretty easy for any outsider to see that things have gotten out of hand. But when designing software, that bad habit becomes significantly harder to spot.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build a solid Foundation to prevent Feature Creep
&lt;/h3&gt;

&lt;p&gt;How do you know whether a feature is going to improve or bog down your design? To answer this question, you need to have a firm understanding of what your product’s use case is. Before beginning a project, you should answer the following questions as thoroughly as possible.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Who is this product for?&lt;/li&gt;
&lt;li&gt;When will people use this product?&lt;/li&gt;
&lt;li&gt;What do I want people to feel while using this product?&lt;/li&gt;
&lt;li&gt;How will this product be differentiated from similar products that already exist?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s important to note that the answers to these questions are not features, they’re probably not even user stories. You shouldn’t say that ‘My product will have features X, Y, and Z’, because you may find in prototyping those features don’t work as well as you thought. Instead, you should say ‘My product will help consumers solve problem X”. That way, the driving focus for your product is explicit, and you/your team have a metric to compare different implementations. &lt;/p&gt;

&lt;p&gt;Once you’ve answered these questions, write them down and treat them as gospel. Whenever you need to make a design decision go back to your answers and ask yourself “Do I &lt;em&gt;need&lt;/em&gt; to have this feature in order to justify my answer?” And you should only implement that decision if the answer is a resounding yes. These foundational questions also provide a benchmark for who close to complete your project is. After all, you’re not done until you can check off every part of your foundation.&lt;/p&gt;

&lt;p&gt;But how can you decide the best method for accomplishing the goals you’ve set out for yourself? How do you know whether feature A or feature B is a better fit for your product? &lt;/p&gt;

&lt;h2&gt;
  
  
  Customer Feedback
&lt;/h2&gt;

&lt;p&gt;There’s only one way to understand what user experience you’re creating, and that’s to put your product in front of users. Frequent cycles of prototyping and testing are necessary to ensure that you’re putting out the best product possible. There are many ways to gather customer feedback, depending on the resources that you have available. &lt;/p&gt;

&lt;p&gt;Many mobile app companies randomly send different updates out to users, and then look at data to compare how users are responding to each version of the update. Monitoring how much time users spend interacting with your product or which features they use most frequently is a great set of data as well if you can implement systems to track it. But the most basic method is tried and true: simply asking users questions about their experience.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“If I had asked the people what they wanted, they would have said faster horses” &lt;br&gt;
– Henry Ford&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The bad news is that that’s much easier said than done. There are many hurdles to getting useful feedback from users. Unfortunately, when asked ‘How did you like the product?’, most people don’t automatically respond with well thought out criticism and relevant feedback. If you want actionable information, you’re going to have to prod your customers in the right direction with leading questions. &lt;/p&gt;

&lt;p&gt;As a general rule, you should try to keep your questions as specific as possible. You want to ask questions that will force the user to think about their experience and provide critical and specific feedback (with examples and anecdotes if possible). Each question should be directed and have a defined purpose. Also, you probably shouldn’t ask the same set of questions each testing cycle, focus on refining a few features at a time.&lt;/p&gt;

&lt;p&gt;When I run playtests for tabletop or board games, the questions I ask tend to be the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(After explaining the premise but before play) &lt;strong&gt;What are you most excited to do or try?&lt;/strong&gt; – This helps me understand how well my pitch/promotional material is setting expectations. If they are expecting something totally off base, I need to improve the clarity of my writing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What was the most confusing or frustrating part?&lt;/strong&gt; – This tends to be the first question I ask after a playtest. It forces the player to think through the session, and whatever they say will be a form of criticism. I find that a lot of groups are a little hesitant to bring up the negative parts of their experience. This question is good at setting the tone of the discussion and getting everyone in the right mindset.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why did you choose option X over option Y?&lt;/strong&gt; – I want players to be making choices during the experience, but I want to make sure the reasons behind those choices are more along the lines of ‘X is what made sense at the time’ instead of ‘X is obviously better than Y’.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What was the most interesting or memorable thing another player did?&lt;/strong&gt; - I have some mechanics in my game that encourage players to pay attention to and support one another. I don’t really care about the specifics of their answer here. I’m actually just checking that their answer isn’t ‘I don’t know’, because that would mean my mechanics are failing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Interpreting the Data
&lt;/h3&gt;

&lt;p&gt;We’ve collected all of our feedback for the testing cycle. We’ve asked our questions, written down all their answers, and maybe even have some nice objective data recorded automatically. So now all we have to do is just implement the fixes the customers suggested. Easy, right?&lt;/p&gt;

&lt;p&gt;I wish.&lt;/p&gt;

&lt;p&gt;It turns out that the truth is often quite obscured in feedback. Customers can fail to notice key features, misattribute perceived problems, and make incorrect assumptions. Many people are quick to jump straight to features in their feedback, detailing ‘solutions’ that either miss the mark or don’t fit your design goals. Even seemingly objective data can be mired by survivor bias or affected by unseen factors. There are a lot of stories out there about customers complaining about a product for the wrong reasons. &lt;/p&gt;

&lt;p&gt;Here’s a famous anecdote from the development of 2003’s Wolfenstein: Enemy Territory. Wolfenstein was a standard WWII shooter, with multiplayer pitting Axis and Allies teams against one another. During playtesting, a massive number of players found the Allies’ Thompson submachine gun vastly superior to its Axis counterpart, the MP40. This greatly surprised the development team, because the two guns had identical stats. The only difference between the two guns were model and sound effect, yet players consistently felt the two guns were very different. “The general consensus was that if you had a Thompson, it was slower but harder hitting, and the MP40 was faster, but it was weaker” recounted one developer. Even more surprising to the team was that the players were &lt;em&gt;right&lt;/em&gt;. When they looked at the game stats, the Thompson scored a much higher ratio of kills than the supposedly identical MP40. After a thoroughly confused examination, the team came to the conclusion that the difference was due to the sound effects produced by the two guns. The Thompson’s gunshot had significantly more bass than the MP 40’s. It sounded more powerful, players felt more confident, and that confidence led to them attempting headshots at a higher rate than players with the MP40.  The ‘fix’ for this issue only involved reducing the bass on the Thompson’s shots. Afterward, players felt that the gun had been ‘brought down’ to the proper power level. &lt;/p&gt;

&lt;p&gt;It’s important to properly understand the moral of this story. Even though there technically wasn’t a problem, customers perceived one, and believed it so strongly that it actually warped the collected data. This invented problem still made customers unhappy, and it would have driven them away if left unchecked. In that sense, the perceived problem was just as real as any other.&lt;/p&gt;

&lt;p&gt;So, when you have your data, and you notice a strong trend, don’t just take it at face value. Investigate, iterate, and test possible solutions, because the real problem might be something everyone has taken for granted.&lt;/p&gt;

</description>
      <category>design</category>
    </item>
    <item>
      <title>Thinking through Algorithms</title>
      <dc:creator>nwdunlap17</dc:creator>
      <pubDate>Tue, 10 Sep 2019 15:58:55 +0000</pubDate>
      <link>https://dev.to/nwdunlap17/thinking-through-algorithms-hc0</link>
      <guid>https://dev.to/nwdunlap17/thinking-through-algorithms-hc0</guid>
      <description>&lt;h2&gt;
  
  
  Your Brain is Too Smart for Simple Algorithms
&lt;/h2&gt;

&lt;p&gt;I imagine most people want to start programming for the same reasons I did. Growing up, I thought computers were these brilliant things that could simulate entire worlds, learn how to solve puzzles, and hold millions of books worth of information. And that made it really hard for me to realize one very basic truth about programming. Computers are &lt;em&gt;morons&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;This truth is one of the most common hurdles for new programmers. They see a relatively simple algorithm and they don’t even know where to start. It isn’t that they’re too stupid to find the solution, the problem is that they’re too smart to see there’s a problem at all!&lt;/p&gt;

&lt;p&gt;Here is one of the simplest algorithms in the word. What’s the largest number in the following list?   &lt;/p&gt;

&lt;p&gt;3,  7,  4&lt;/p&gt;

&lt;p&gt;It’s seven. Obviously it’s seven. If I asked you how you know it was seven, you’d probably look at me like I just asked you what color the sky is. You just &lt;em&gt;know&lt;/em&gt; its seven from looking at it! And that’s the problem, your brain is so smart, it just skips over all of the work it did and gave you the answer. But computers are morons, and it can’t do what you can do. One of the first steps of algorithm design is training yourself how to think at a lower level. Ask yourself ‘How do I know that?’ enough times, and eventually you’ll be reach a level the computer will understand. (Assuming you don’t veer off into philosophy, that’s Descartes’ territory). &lt;/p&gt;

&lt;p&gt;Here’s the same question again, find the largest number in the list. But this time, think about what exactly you’re doing, talk to yourself if you have to, whatever it takes to do this task as slowly as you can.&lt;/p&gt;

&lt;p&gt;9, 1, 16, 2, 3, 7, 14, 5, 10, 15, 7, 12, 8, 4, 19, 10, 17, 8, 13&lt;/p&gt;

&lt;p&gt;Of course, the answer is nineteen. But for a while, you were probably thinking the answer could be sixteen. You probably saw sixteen was the highest number on the left side, and then went looking for a number bigger than 16. You reached the fifteen, and in the back of your mind, whether you knew it or not, you thought “Fifteen isn’t bigger than Sixteen. Sixteen is still the biggest number”. When you reached the nineteen, the opposite happened, you knew that nineteen was the biggest number.&lt;/p&gt;

&lt;p&gt;So basically, you remembered what the biggest number you saw was, and you checked all the other numbers against it. When you found a bigger number, you remembered that one instead. And that level of simplicity is absolutely something you can communicate to your computer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;biggest_number(number_array)
      biggest_number = first number in number_array
      for each next_number in number_array
            if(next_number &amp;gt; biggest_number)
                  biggest_number = next_number
            end
      biggest_number
end 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Admittedly, that’s not too much to write home about. Finding the largest number in a list doesn’t sound very impressive. But these skills are applicable to much harder algorithms. Let’s try one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making Assumptions
&lt;/h2&gt;

&lt;p&gt;I’m going to give you a couple of coordinates on a 2D grid.  You have to design an algorithm to determine which straight line passes through the highest number of points.&lt;/p&gt;

&lt;p&gt;[1,3], [2,1], [3,2], [4,3]&lt;/p&gt;

&lt;p&gt;[2,2], [2,4], [3,2], [2,3], [3,3], [2,5], [4,4]&lt;/p&gt;

&lt;p&gt;That’s quite rude of me, isn’t it? After all, there are infinitely many lines on a 2D grid, how on earth are you going to tell your stupid computer not to look at them all? Let’s start by drawing out the problem to see if we can wrap our heads around it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;|                               |      o            o
|o                 o            |      o      o
|            o                  |      o      o 
|      o                        |      o
|___________________            |___________________
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That’s a lot better! It’s pretty easy to see that in the first graph, the right 3 points make the longest line, and in the second graph it’s the 4 vertical points. You certainly didn’t need to look at every possible line to figure that out! In fact, I’m willing to bet that you didn’t even think about vertical lines while looking at the first graph.&lt;/p&gt;

&lt;p&gt;Your eye was drawn to the points, not the whitespace. What probably happened is that your eye found two points, and &lt;em&gt;followed the line they made&lt;/em&gt;. You kept track of which line had the highest number of points just like in the previous algorithm, and when you had looked at all the lines you cared about, you knew which one was the longest.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;best_line(points_array)
      for every point in points_array
            for every other_point in points_array
                  Find the line between the points (y = mx+c)
                  count = 0
                  for every potential_point in points_array
                  if (potential_point is on line) {count += 1}
            end
      end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Your brain has evolved over millions of years to be good at finding patterns, to solve most algorithms, you just need to break down what it’s doing into simple and concrete steps. If you get into the habit of figuring out what your brain is doing, you’ll be able to quickly and carefully build your algorithms.&lt;/p&gt;

&lt;p&gt;The next part of this post is about making algorithms faster. This comes with a big caveat. &lt;br&gt;
&lt;strong&gt;Most of the time, the most important thing is just finding a solution.&lt;/strong&gt; In interviews and in applications, the most important thing is to quickly find any solution. This allows you to demonstrate your understanding to an interviewer, or to test other segments of your code. You should only be worrying about improving the performance of your algorithm after you have one that works.&lt;/p&gt;
&lt;h2&gt;
  
  
  What makes an algorithm good?
&lt;/h2&gt;

&lt;p&gt;There are a few criteria that algorithms can be judged on. The ‘best’ form of algorithm in an application will probably heavily rely on one of these criteria. For an interview, there typically is no ‘best’ answer, but good answers tend to balance the three (or at least, keep the performance across all criteria reasonable). Being able to evaluate your answer in an interview is also a huge plus, as it shows that you have a good understanding of ways you could try to improve it. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simplicity: How easy it is to understand the algorithm when you see it in code. &lt;/li&gt;
&lt;li&gt;Scalability/Speed: How long does the algorithm take to complete? And how much longer does it take to complete when you double the amount of data.&lt;/li&gt;
&lt;li&gt;Size: How much memory does the computer need to complete the algorithm.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rest of this post will focus on scalability/speed. If you devise an algorithm based on the principle of ‘What is my brain doing?’, then you’ll probably already have a very simple and intuitive algorithm. And significantly reducing algorithm size usually involves some very technical tricks that are specific to the language.&lt;/p&gt;
&lt;h2&gt;
  
  
  Start Answering before they Stop Asking
&lt;/h2&gt;

&lt;p&gt;If you’ve ever watched Jeopardy, you know that the most successful contestants are the ones that are hitting the buzzer before Alex Trebek is done reading the question. Following the methods described above will help you get an answer to the problem, but they may not help you get the fastest answers. The following two problems are taken straight from Google interviews, and they’re both about solving the problem as quickly as possible.&lt;/p&gt;

&lt;p&gt;One of the biggest factors in algorithm speed is iteration time. How many times do you need to go through your data? When we were finding the biggest number, we only had to go through the list once. If we double the length of the list, the time it takes to find the biggest number will double. When we were finding the most populated line, we had to check every pair of points. If we double the number of points, the time taken to find the line will quadruple. Obviously, we would much prefer the former to the latter, because the time stacks up very quickly.&lt;/p&gt;
&lt;h3&gt;
  
  
  Getting as much information as possible
&lt;/h3&gt;

&lt;p&gt;If you’ve never heard of them, linked lists are data structures where each member points to the next member. They’re very useful because they can be scaled infinitely, and they take up about as little memory as possible, since there’s no overhead keeping them organized. The downside to linked lists is that they are a pain to navigate, since you can only start from the beginning and travel forward one entry at a time.&lt;/p&gt;

&lt;p&gt;The google problem is this: find the middle node in a linked list, but you can only use a single loop. This restriction immediately prevents the obvious solution: go through the list, count the number of elements, then go through half again as many nodes to find the half-way point.&lt;/p&gt;

&lt;p&gt;The trick here is to get the maximum amount of information from each node that we can. If we stop and consider exactly what we know at each step, we can solve this problem in a single loop. One way to do this is to assume that any node we visit could be the last node and prepare an answer for if that is true.&lt;/p&gt;

&lt;p&gt;Let’s run through what that looks like:&lt;/p&gt;

&lt;p&gt;We start at the first node, if this is the only node in the list, then it is the middle node as well.&lt;/p&gt;

&lt;p&gt;When we reach the second node, the first node is still the middle node.&lt;/p&gt;

&lt;p&gt;When we reach the third node, we know that the first node cannot possibly be the middle node. If this is the last node, the second node is the middle node.&lt;/p&gt;

&lt;p&gt;If we reach the fifth node, the third node is the current middle node.&lt;/p&gt;

&lt;p&gt;Extrapolating from this, every two nodes we move forward, the middle node advances by one. We can continue this pattern until we reach the end of the list, and then immediately return the middle node we have prepared.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Find_middle(linked_list) 
fast_pointer = linked_list.first 
half_pointer = linked_list.head
while (fast_pointer != null)
      fast_pointer.next
      fast_pointer.next
      half_pointer.next
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Finding the Sum with a Hash Table
&lt;/h3&gt;

&lt;p&gt;Given a list of numbers, find the pair of numbers whose sum is a chosen number. &lt;/p&gt;

&lt;p&gt;Find the numbers that sum to 12 in the following list:&lt;/p&gt;

&lt;p&gt;2, 5, 8, 6, -3, 14, 4, 1, 3, 12&lt;/p&gt;

&lt;p&gt;Following a similar theory to the algorithm above, if we keep potential answers in mind, we can solve this problem very quickly. For example, the first number is 2, this means that if we ever find a 10 in the list, we can safely ignore any remaining numbers in the list, as we have already found the answer. Eventually, we will reach 4, and realize that we already have an 8, thus completing the sum.&lt;/p&gt;

&lt;p&gt;The issue with this problem is how to compare the potential answers we’ve found to our current number. If we store the potential answers in an array, then we aren’t actually saving any time at all, as we’ll be examining that array once for every number in the original array. Instead, we have to use a hash table.&lt;/p&gt;

&lt;p&gt;A hash table is a special kind of data structure. Unlike an array, it is expensive to iterate through a hash, but it is very quick to check for a specific value. To solve this problem, we simply need to check if the current number already exists in a hash of potential answers, if it doesn’t, add the next potential answer to the hash.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Find_sum(array, sum)
potential_answers = {}
For each num in num_array
      if (potential_answers[num] == true) { return [num, sum-num] }
      else{ potential_ansers[sum-num] = true }
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>beginners</category>
    </item>
    <item>
      <title>An Introduction to Yield in Ruby, and filtering class instances</title>
      <dc:creator>nwdunlap17</dc:creator>
      <pubDate>Fri, 06 Sep 2019 06:21:06 +0000</pubDate>
      <link>https://dev.to/nwdunlap17/an-introduction-to-yield-in-ruby-and-filtering-class-instances-549j</link>
      <guid>https://dev.to/nwdunlap17/an-introduction-to-yield-in-ruby-and-filtering-class-instances-549j</guid>
      <description>&lt;h2&gt;
  
  
  Keep your code DRY by avoiding WET
&lt;/h2&gt;

&lt;p&gt;Everyone that’s been programming for a while knows the value of keeping your code DRY (Don’t Repeat Yourself). The last thing that you want to do is have WET (Written Everything Twice) code. That’s right, it’s such an important concept that there’s &lt;em&gt;two&lt;/em&gt; acronyms for it!&lt;/p&gt;

&lt;p&gt;There are many benefits to keeping code as DRY as possible.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It’s usually faster to turn a chunk of repeated code into a method, that way the next time you have to call it, you can do so in one line.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you need to change your code, you only need to do so in one spot.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your code is far easier to understand if every section is unique. Otherwise you risk reviewers looking at a section, saying ‘I’ve seen this before’, and not noticing that &lt;em&gt;this time&lt;/em&gt; it’s a tiny bit different.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So it’s always good practice to put any repeated code into a method that can be called repeatedly. But what about those times when you &lt;em&gt;do&lt;/em&gt; want to change your code block very slightly? For those instances, you have the &lt;em&gt;yield&lt;/em&gt; keyword.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Yield Works
&lt;/h2&gt;

&lt;p&gt;The yield keyword allows you to temporarily pass control from the function in the middle of its execution. Essentially, you can build a function that has a &lt;em&gt;yield&lt;/em&gt; in it, and then &lt;em&gt;you can replace that ‘yield’ with code of your choice every time you call the function&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;When you call a function with a yield, you include a block of code, surrounded by curly braces, that will replace any instance of the yield keyword. The following two functions have identical outputs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="no"&gt;Hello&lt;/span&gt; &lt;span class="no"&gt;World&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; “Hello World!”&lt;/span&gt;


    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;hello2&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="no"&gt;Hello&lt;/span&gt; &lt;span class="no"&gt;World&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; “Hello World!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Multiple yields can be used in the same function, and each one will be replaced by the same code block.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;double&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;double&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="no"&gt;Hi&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt;”Hi!Hi!”&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Of course, code blocks would be fairly useless without the ability to pass variables through the yield. In the below code snippet, the &lt;em&gt;name&lt;/em&gt; variable is passed to the yield block, where it is called &lt;em&gt;person&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="no"&gt;You&lt;/span&gt; &lt;span class="n"&gt;see&lt;/span&gt; &lt;span class="c1"&gt;#{name}. ”&lt;/span&gt;
        &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="no"&gt;Dave&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="no"&gt;Hi&lt;/span&gt; &lt;span class="c1"&gt;#{person}!”} #=&amp;gt; ”You see Dave. Hi Dave!”&lt;/span&gt;
    &lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="no"&gt;Dave&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="c1"&gt;#{person} says hello!”} #=&amp;gt; ”You see Dave.         &lt;/span&gt;
&lt;span class="no"&gt;Dave&lt;/span&gt; &lt;span class="n"&gt;says&lt;/span&gt; &lt;span class="n"&gt;hello!&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You may have noticed in the last example that yield but life a bit easier for us. Notice that in the above two examples, we put the name at either the beginning or end of the second sentence. If we were passing the rest of the sentence into a function, we would need a bit of extra logic to determine where exactly the name should go. But thanks to yield giving us direct access to the variable inside the function, we can easily put it where we want.&lt;/p&gt;

&lt;h2&gt;
  
  
  Functions vs Yield Blocks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The same functions can be called multiple times, but a yield block must be written in its entirety every time a function must yield. Therefore it is best practice to use the function for as much as possible, and only use yield for the mutable parts of the code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Yields and functions work identically for passed variables. Yield functions &lt;strong&gt;only have access to the variables passed to it when it is called&lt;/strong&gt;, just like functions. Variables will be passed to yield in the default manner; this means that changing an integer, string, or float in a yield will not affect the value outside the yield; but changing an array or hash will.   &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;strong&gt;return&lt;/strong&gt; keyword ends the functions that the yield is in. This means that anything that appears after the yield will not execute. This is something you’ll probably want to avoid in most cases, so just use implicit return.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Within the function containing yield, you can treat yield as a function for the purposes and syntax of passing it values and retrieving values from it. For example, if a yield block takes in a string and returns an array, you can use &lt;em&gt;yield(string)[3]&lt;/em&gt; to pass in the string and get the 4th element of that array. You can also set variables equal to the output of yield: &lt;em&gt;foo = yield&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Using Yield with Class Iterators
&lt;/h2&gt;

&lt;p&gt;One of the most common uses of yields is adapting classes for use in iterators. Imagine that we have a People class, and that each instance of this class has various attributes: name, age, career, etc.. If we wanted to make functions that could easily filter out specific people, we might have a few functions that look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;filterPeopleByAge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;minAge&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;maxAge&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;people&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
            &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;minAge&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;maxAge&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;filterPeopleByAge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="c1"&gt;#Returns everyone between 18 and 26&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;filterPeopleByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;people&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
            &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first_name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;filterPeopleByName&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="no"&gt;Dave&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="c1"&gt;#Returns everyone named Dave&lt;/span&gt;


    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;filterPeopleByOccupation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;occupation_array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;people&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
            &lt;span class="n"&gt;occupation_array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;occupation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;filterPeopleByOccupation&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="no"&gt;Doctor&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="no"&gt;Lawyer&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="no"&gt;Professor&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; 
    &lt;span class="c1"&gt;#Returns all doctors, lawyers, and professors&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But that certainly seems like a lot of repeated code. We’re only changing a single thing across each of those functions: the filter condition. We can’t simply write a function that can handle searching across every possible attribute (at least, not one that’s tidy or easily legible). But by using a yield, we can directly control the condition statement. The function and yield below can perform the role of the above functions in a much shorter and more legible manner.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;filterPeople&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;people&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;filterPeople&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="c1"&gt;# Returns all people between 18 and 26&lt;/span&gt;
    &lt;span class="n"&gt;filterPeople&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="no"&gt;Dave&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="c1"&gt;#Returns all people whose first name is Dave&lt;/span&gt;
    &lt;span class="n"&gt;filterPeople&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;         
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="no"&gt;Doctor&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="no"&gt;Lawyer&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="no"&gt;Professor&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;occupation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="c1"&gt;#Returns all doctors, lawyers, and professors&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This generic function is even more powerful than the previous set of functions for three reasons. First, it's still just as valid even if we add additional attributes to the person class. Second, it only takes one line to call and create new search criteria. And finally, we can easily use it to combine search criteria.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;    &lt;span class="n"&gt;filterPeople&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;occupation&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'Lawyer'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;#Returns all lawyers under 40&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  An even MORE generic solution
&lt;/h2&gt;

&lt;p&gt;The previous search function looks pretty good on paper, but in practice it has a glaring flaw. Yield ONLY has access to values that are passed to it from the yielding function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;filterPeople&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;people&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;minAge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;
    &lt;span class="n"&gt;maxAge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;
    &lt;span class="n"&gt;filterPeople&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;minAge&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;maxAge&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;#THIS DOES NOT WORK. The yield cannot access the Age values because they were not passed in during the filterPeople function. &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If we want to be able to have a smarter search function, we need to allow it to accept some parameters. We'll create a generic array &lt;em&gt;args&lt;/em&gt; that we can use to hold our criteria.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;filterPeople&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;people&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now we are freely capable of passing parameters to the yield through the function. And because the function and yield block are all called together, it should be fairly legible as to what args[foo] is referring to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;    &lt;span class="n"&gt;minAge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;
    &lt;span class="n"&gt;maxAge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;
    &lt;span class="n"&gt;filterPeople&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;minAge&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;maxAge&lt;/span&gt;&lt;span class="p"&gt;]){&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;


    &lt;span class="n"&gt;minAge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
    &lt;span class="n"&gt;occupations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Artist'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'Race Car Driver'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'Athlete'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;filterPeople&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;minAge&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;occupations&lt;/span&gt;&lt;span class="p"&gt;]){&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;occupation&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now we have a function which allows us to create any arbitrary search criteria that we want for the Person class! And we can call it on a single line no less!&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Ruby Console Applications for Beginners: Making Menus with Curses</title>
      <dc:creator>nwdunlap17</dc:creator>
      <pubDate>Mon, 26 Aug 2019 01:30:56 +0000</pubDate>
      <link>https://dev.to/nwdunlap17/ruby-console-applications-for-beginners-making-menus-with-curses-4n6p</link>
      <guid>https://dev.to/nwdunlap17/ruby-console-applications-for-beginners-making-menus-with-curses-4n6p</guid>
      <description>&lt;h2&gt;
  
  
  Console applications and some History
&lt;/h2&gt;

&lt;p&gt;Console applications are some of the most useful in a programmer’s toolbelt. The terminal is the simplest user interface, but it is still versatile enough that it can serve as an effective front-end for most programs. And because it has no need for graphics, you can save time, money, and space!  &lt;/p&gt;

&lt;p&gt;The downside, of course, is that the terminal looks and feels as simple as it is to implement. Navigating anywhere requires typing the correct input and hitting the enter key. And if the user makes a typo? They have to type everything again! Even using simple number or yes/no menus feels sluggish because of the need to hit the return key after every input. Fortunately, there’s a way to make the terminal UI sleeker and faster, and that’s with Curses.&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%2Fmedia.tenor.com%2Fimages%2F76544063e9fe2270ab09f77e01d52e74%2Ftenor.gif" 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%2Fmedia.tenor.com%2Fimages%2F76544063e9fe2270ab09f77e01d52e74%2Ftenor.gif" alt="No, not those kind of curses."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Curses is a library that gives you easy and direct control over the terminal screen.  It was first written in the late 70’s by Ken Arnold because he found the conventional terminal interface too limiting to make engaging games. (Fun fact, one of the first games he built with curses was Rogue, which went on to become a cultural touchstone for geeks everywhere). Curses has been mostly unchanged since the early 90’s, and can be utilized in pretty much every modern programming language, so it has a pretty strong pedigree. &lt;/p&gt;

&lt;h2&gt;
  
  
  The One Complicated Thing
&lt;/h2&gt;

&lt;p&gt;That brief history wasn’t just a bit of trivia, it goes a long way toward explaining one of Curses weirdest features. Changing the text on the screen used to take a fair bit of computing power, and if multiple sections of text needed to be updated, there could be a pretty significant delay as the computer ran through all the changes. Ken’s answer to this was to create a buffer that stored what the screen should look like, then update the whole screen at once.&lt;br&gt;
This logic carries over to how Curses works today. &lt;strong&gt;When you write something in Curses, it updates the buffer, it DOES NOT display on screen&lt;/strong&gt;. You have to tell the screen to update in order to see any of your changes. While that may sound like a bit of a hassle, there’s a reason it’s been kept this way for forty years. Since all text on screen is updated at once, your users will never see a half-finished frame. This means that your programs will look cleaner, and simple animations are possible by quickly changing frames.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fek2wtz5j077sxn8vy77n.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fek2wtz5j077sxn8vy77n.png" alt="The screen will display whatever is in the buffer when refresh is called. And only that."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The 6 Basic Curses Commands
&lt;/h2&gt;

&lt;p&gt;Part of the reason curses is so widely used is because of its simple syntax. All of Curses’ functionality can be accessed through a total of 6 commands. While there are many more that can be used, those methods can all be reproduced using these 5.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Curses.setpos&lt;/strong&gt;(int1,int2) – Sets the position of the cursor. The first number is the line (starting from 0 at the top), and the second is the number of characters into the line (starting from 0 on the left).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Curses.addstr&lt;/strong&gt;(string) – Writes the text into the buffer, starting from the current cursor position. Any text that already exists in that space will be overwritten.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Curses.refresh&lt;/strong&gt; – Displays on screen everything that is currently in the buffer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Curses.clear&lt;/strong&gt; – Removes everything from the buffer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Curses.getch&lt;/strong&gt; – Waits for the user to press any key, returns the character as a string.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Curses.init_screen&lt;/strong&gt; – Used to setup which area of the terminal Curses will run on. If given no arguments, it defaults to the entire terminal.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;A simple application&lt;/strong&gt;&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F1erszscrd34sm8v5tcm5.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F1erszscrd34sm8v5tcm5.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, we require curses so that the app knows that it has access to the Curses library.&lt;/p&gt;

&lt;p&gt;We add the strings ‘Hello,World!’ and ‘ Press any key…’. Note that because we did not change the position of the cursor in between these two strings, the second string starts right where the first one lets off. The refresh command only displays what we have already written into the buffer.&lt;/p&gt;

&lt;p&gt;The ‘This won’t appear until you press a key’ string is added to the buffer, but there is no refresh following it, so it hasn’t appeared on the screen yet. Once the Curses.getch command is hit, the program stops and waits until a key is pressed.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8hkquzkxinu3muds2a6m.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8hkquzkxinu3muds2a6m.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pressing the key ‘f’ causes it to be written to the cursors current position (the end of the first line). It also causes the key variable to become the string ‘f’. The position of the cursor is changed to the 6th line down, eleventh character in, and another string is written to the buffer. A refresh then displays all of the changes made to the buffer.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fhy5so7vq0yxfyqqyqxpy.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fhy5so7vq0yxfyqqyqxpy.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The final getch exists to catch the program before it ends. Once the program ends, the curses window closes and all of the displayed text disappears.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making Menus
&lt;/h2&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fkt2oo13gs1av99mlgw54.jpg" 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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fkt2oo13gs1av99mlgw54.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The lower left section of this screenshot shows a simple example of a menu you can make using curses. It displays the elements of an array as a list, and the user can navigate the list and choose one entry. Let’s break down all the steps that are happening to render this menu.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Build our options&lt;/strong&gt; - For each option, we need a string to display to the user and an object to return.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Keep track of where the Cursor should point&lt;/strong&gt; – We use a variable called ‘index’ to store the current position of the arrow &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Start a Loop&lt;/strong&gt; – The rest of the logic takes place inside of a loop, this will handle showing the menu to the user and reacting to their inputs.&lt;br&gt;
a. &lt;strong&gt;List The Options&lt;/strong&gt; – For every option in the list, we add its name to a line in the buffer&lt;br&gt;
b. &lt;strong&gt;Place the Arrow&lt;/strong&gt; – We draw the arrow on a line determined by the index&lt;br&gt;
c. &lt;strong&gt;Draw the Menu&lt;/strong&gt; – We use Curses.refresh to display the menu we’ve built&lt;br&gt;
d. &lt;strong&gt;Get User Input&lt;/strong&gt; – Using Curses.getch, we can get input from the user. Notice that we always have to update the screen BEFORE getting input from the user, otherwise the user won’t be looking at the current state of information.&lt;br&gt;
e. &lt;strong&gt;Interpret Input&lt;/strong&gt; – We check if the user wants to change the index or select the current entry. If the user wants to make a selection, the loop ends and the selection value is returned&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the below example, the menu has been broken down across a couple different methods for clarity.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;menu.start&lt;/strong&gt; takes in arguments for the menu, calls the other methods to do all of the above logic, then finally returns the selected value wherever it was called. (Step 1)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;initialize&lt;/strong&gt; makes an instance of the menu, and sets the default value of the variables. (Step 2)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;display&lt;/strong&gt; handles all of the drawing and rendering. (Steps 3a-3c)&lt;/li&gt;
&lt;li&gt;Finally, &lt;strong&gt;menu_loop&lt;/strong&gt; handles the loop and all of the other step 3 logic.&lt;/li&gt;
&lt;/ul&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F298s81uudhx4b4s1bk6t.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F298s81uudhx4b4s1bk6t.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice that Curses.clear is never called during the menu loop. This means that whatever is on the screen will stay on the screen while the menu is up. However, this also means that we must manually overwrite text when we want it to disappear: this is why we add some whitespace before each choice to remove the arrow from its last position.&lt;br&gt;
Also notice that we used some additional variables to check the total size of the list. That way, we can easily loop the index around when the user moves it past the end.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Menus are Awesome
&lt;/h2&gt;

&lt;p&gt;Let’s take a quick look at some of the advantages this provides over text parsing menus.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It’s Fast&lt;/strong&gt; – A problem with text parsing menus is that they require the user to hit Return for every entry. This can slow things down considerably when they make multiple options in succession. Additionally, instead of having to search for the right button for an option, this menu only requires three buttons: (up, down, and select)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It’s Intuitive&lt;/strong&gt; – In a text parsing menu, a user might not know whether they should type ‘Spiderman’, ‘Spider Man’, or ‘Spider-Man’. If the user is picking from a menu, and not typing the name, they can’t make this mistake.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It Protects the Program from Error&lt;/strong&gt; – Because the menu class can only ever return an object that it was given, you don’t need to verify that the user inputs are appropriate. If the user puts in an incorrect input, that error only needs to be handled inside the menu class, rather than checked for every time the program asks for an input.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It’s Universal&lt;/strong&gt; – This menu class can be used regardless of the type of object in the array. When I was making my game, I used this same menu class in my game to handle choosing doors, characters, skills, targets, and equipment. And for most of those selections, I only needed a single line of code to call the menu.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With curses, you can improve your console applications with menus that look and feel much more professional. And if you do it right, it can save you a ton of time and effort dealing with bugs.&lt;/p&gt;

&lt;h2&gt;
  
  
  More Curses
&lt;/h2&gt;

&lt;p&gt;This post is only meant to be a short introduction to Curses and some of the things it can do. Feel free to use or adapt any of the code provided in this post for your own projects. If you want a more comprehensive look at Curses, including its incredibly useful window commands, I recommend &lt;a href="https://stac47.github.io/ruby/curses/tutorial/2014/01/21/ruby-and-curses-tutorial.html" rel="noopener noreferrer"&gt;this tutorial&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
