CS 312 Software Development

CS 312 - Practical One

Goals

  • Get started with basic JavaScript and Node.js
  • Get started with Git, GitHub classroom, repl.it, and Gradescope

In this practical, you are going to create a simple JavaScript module to get a feel for some basic JavaScript principles and start getting familiar with our tools.

Start a repl

Go to the team page. Click the "Start project" link for "Practical 1".

After some of the issues we faced with section A, we are converting over to a project model. Ignore the "Create a new repl.it" section if you are starting fresh.

Create a new repl.it

For this practical, we will start from scratch to help you understand what is going on behind the scenes. Future assignments will make use of starter templates so you don't have to worry about all of the details.

Go to Repl.it and create a new repl using one of the many buttons scattered around the interface (almost every screen on the website has a new button lurking in some corner). Chose Node.js as the language, and name the repl practical01-username, where username is your username (you can use you Midd, GitHub, or repl.it username, though your GitHub would be the most consistent with later assignments).

Select "Private" for the viewing permissions.

Select the "Create repl" button.

When it is complete, you should have a new repl with a single file: index.js in it.

Finding your way around

By default, when you open up a new repl, you will see three columns: the first is the file browser (among other things), the second is the editor, and the third is Console/Shell.

The REPL

Since this is a Node.js (i.e., command line JavaScript) project, the Console is running a Node REPL. REPL stands for read-evaluate-print-loop. You can think of this as a JavaScript interpreter, just as you have seen in Python. This concept is where repl.it gets its name from -- unfortunately, branding considerations meant they call individual projects "repls". This is partially accurate since their goal really is REPL on a large scale, but it is slightly misleading.

You can type any kind of JavaScript into the REPL running in the Console. Try the following:

let x = 42

The REPL should come back with undefined, since assignment statements have no return value. If you just type x alone at the prompt, it should return the value stored in the variable.

The editor

The editor isn't the most full featured coding environment you will ever use, but it is good enough for our purposes. You can do a little configuration using the gear icon on the far left.

If you type into the file, it will auto-save. When you want to try something, you can click the "Run" button at the top of the page. This will reload the Node environment and run the contents of the JavaScript file. Try it out, create a new variable in the file and click the "Run" button. The Console should blank out and then you should be able to use the variable you created in the REPL.

Writing some functions

Let's write a couple of functions to get a feel for how that works, and to give you a chance to experiment with them.

Summation

I would like you to write a function that sums all of the values in an array.

For our first pass, let's write the code using a conventional for loop. Create a new function called summationFor.


const summationFor = (list)=>{


};

For loops in JavaScript look a lot like they do in Java/C/etc... To iterate over the indices of a list, we would use:

for (let i = 0; i < list.length; i++){
}

Finish that function up and test it in the REPL.

As you should know from the lecture, we wouldn't really use a for loop for this. Write a second function called summationForEach. You will replace the for loop with a forEach. The forEach function is a method of arrays. Recall that it is a higher-order function that takes in a function as an argument. The forEach function calls the function you pass in once per element of the array, passing the element in as the first argument ot the provided function.

Test your function in the REPL to make sure it works.

Even this approach is more iterative than we really would use for a problem like this. I would like you to write this function one more time, but this time instead of forEach, you are going to use reduce. reduce is another high-order method of arrays. Its job is to run a function on every element of an array, accumulating a result -- in essence, the array is reduced down to a single value. The function you pass into reduce should have two arguments -- the first is the accumulated value and the second is the current element in the array.

Write a new function called summationReduce, which uses the reduce method to sum the list. Note that reduce is going to do all of the work, so, summationReduce could actually use the implicit return version of the fat arrow syntax (as could the reducer function that you pass to reduce). Test your new function.

When you are happy that the new function is working, try running it on an empty array. You will probably get something that looks like this:

> summationReduce([])
TypeError: Reduce of empty array with no initial value
    at Array.reduce (<anonymous>)
    at summationReduce (/home/runner/practical01-solution/index.js:20:39)
    at repl:1:1
    at Script.runInContext (vm.js:130:18)
    at REPLServer.defaultEval (repl.js:435:29)
    at bound (domain.js:427:14)
    at REPLServer.runBound [as eval] (domain.js:440:12)
    at REPLServer.onLine (repl.js:760:10)
    at REPLServer.emit (events.js:315:20)

The reduce method works by starting with the first element in the array as its initial value. If there isn't one... BOOM! We can fix this by adding a second argument to the reduce function. This becomes the starting value for the reduction. Add in a 0 as the initial value (add it to reduce, not to the reducer function, which already has two arguments).

Try it again -- it should work correctly, even on empty arrays.

Mapping

While we are thinking about higher-order functions, let's try a map example.

I would like you to write a decorate function that returns an array of "decorated" strings.

 decorate(['Sam', 'Penny', 'Jordan'])
[ '-<< Sam >>-', '-<< Penny >>-', '-<< Jordan >>-' ]

Any time that you have an array of values and you need a second array of values reflecting some transformation of each value, you should think map. The helper function you pass to map takes in one value and returns the transformed value. A common error is to think about the array as a whole. Let that go -- the real benefit of using map is that you only really need to think about what happens to a single value.

Write and test the decorate function. Keep the decoration the same so that my auto-checker recognizes your answer.

Exporting functions

In order to make the functions you have written visible to the auto-checker, you need to export them. In essence, this will create a JavaScript module, which behaves like a library in other languages (this is only for backend JavaScript that runs outside of a browser, we will shortly abandon this practice for a different one).

To do this, we will add a module.exports assignment at the bottom of the page.

module.exports = {
  summationFor,
  summationForEach,
  summationReduce,
  decorate
};
What is going on inside this magic invocation?

Your first Git

Now that you have implemented your module, we want to turn the module into a Git repository.

Git is a distributed version control system (VCS). Git, and its "killer app" GitHub, will play a key role in our workflow. At its simplest, a VCS enables us to "checkpoint" our work (a commit in Git terminology), creating a distinct version of our codebase that that we can return to. The opportunity to track and undo changes makes it easier to find new bugs (by reviewing differences to a prior working version), maintain a clean code base (we don't need to keep commented out code around in case we need it again), confidently make large changes knowing we can always recover a working version, and much more. For these reasons and more solo developers will use a VCS (and so should you!), but it is even more useful in a team environment.

How will you know if you and another developer modify the same file (in potentially incompatible ways)? How do you ensure you don't end up with a teammate's half-working modifications? We will use the VCS to prevent these problems.

The "distributed" in "distributed VCS" means that no central repository is required. Each Git repository contains the entire history of the project and thus each developer can work independently, making commits (checkpoints) without interfering with anyone else. Only when you push or pull those changes to another copy of the repository do your changes become visible to anyone else. Further we will use branches to segregate our changes. A branch is just a parallel version of the codebase. This allows you to experiment, while leaving the master branch untouched until your new feature is ready to be merged back into the master.

Git does not require a central repository. However, teams still tend to use a central repository to facilitate their work (we will use GitHub in this role). There isn't anything technically special about the shared repository other than that the team decides to share their changes via that central repository rather than directly with each other, which makes access privileges easier.

We will use Git and GitHub (in concert with Gradescope) to submit our work. Keep in mind the "distributed" in distributed VCS. Until you have pushed your changes to GitHub (and submitted your repository to Gradescope) your work is not turned in.

Repl.it has git incorporated in, so we just need to switch it on.

  1. Click on the second icon down on the left (the one that looks like a graph or a tuning fork) to open the Version Control panel.
  2. Click the 'Create a git repo` button (Do not click the button to connect to GitHub -- that will come later in the instructions)

You now have a git repo and your work to this point has been committed already.

Adding files to your repository is usually a two step process. First you stage the changes you want to preserve (git add) and then you commit the changes, which saves them in the repository. Repl.it's interface rolls these together and provides one button ("Commit & push", which actually does a third thing as well -- it pushes to a remote repository).

For the most part, you will be fine just writing a commit message and clicking the button. However, the command line is still available as well for more fine grained control.

I would like you to take a moment to see how this works.

  1. Create a comment at the top of the file and add your name. (JavaScript comments are the same as Java and C).
  2. Look at the version control panel and observe that it lists the change to the file.
  3. In the right-most panel, click on the "Shell" tab. This will get you a Linux command line.
  4. Type git status. This should show you that the file has been modified.
  5. Type git add index.js. This stages the file (you can also stage whole directories, so git add . stages the current directory, and will catch all changed files).
  6. Type git status again to see how the status has changed. At this point, the changes haven't been saved. Think of this stage as just identifying the things you want to save.
  7. Now commit the changes to the repository with git commit -m "Added name to the top". The "Added name to the top" is the commit message that will be stored with the commit so other developers (and future you) will know what happened in the commit.

Note that the Version Control panel won't detect the change automatically. If you switch the view to the File Browser and then back again you should see it now correctly shows your commit.

You are now ready to submit your practical assignment. Click through to the GitHub classroom assignment. Clicking through to the assignment will create a private repository for you with the name "practical01-<Your GitHub username>.git", e.g. "practical01-ChristopherPAndrews.git". You can view your repository at https://github.com/csci312-s21/practical01-\<Your GitHub username> (click the link provided by GitHub classroom).

On the front page of your new repository, it lists some options about how to get started. We are going to follow the directions for existing repositories. This will add the GitHub repository as a "remote" for your local repository (the one on repl.it). Copy the lines exactly as you see them on GitHub. They will roughly appear be:

  1. git remote add origin repo-name, where repo-name is the name provided by GitHub (don't be the one that actually types out "repo-name"). This connects your local repository to GitHub.
  2. git branch -M main. This is is not actually an essential step for connecting the two repositories. This renames the primary branch of the repository from the git default of "master" to the more inclusive "main".
  3. git push -u origin main. This tells git to copy changes from your current repository to "origin", which is the repository on GitHub.

Once again, the Repl.it Version Control will not know about the command line changes you just made, so switch out and back again. it should not show the branch name as "main" and have a link to your GitHub repository at the top.

If you reload the GitHub page, you will see it now lists your code.

Now, you can submit the practical to Gradescope as described here.

Successfully submitting your assignment is a multi-step process: 1) Commit and push your changes to GitHub, 2) Submit your repository to the Gradescope assignment. Make sure you complete both steps (in order).

Requirements

  • Create Node.js project
  • Write three versions of summation using a loop, forEach and reduce
  • Write decorate using map
  • Setup git and GitHub
  • Submit to Gradescope

Last updated 03/03/2021