6.005 Software Construction
Problem Set 0: Getting Started
Beta Due: 2/9/2013, 5:00pm EST
Code Reviews Due: 2/11/2013 5:00pm EST
Final Due: 2/13/2013, 5:00pm EST

Before you start coding

  • Install the software you'll need on your laptop. You need to install three things for this problem set:

    Athena already has Eclipse, the JDK, and Git installed. To run Eclipse on Athena, follow these steps:

    1. From the terminal, run
      add eclipse-sdk
      to add the eclipse locker to your Athena environment.
    2. From the terminal, run
      eclipse
      to start Eclipse.
    3. Make sure you configure Eclipse to use Java 6 as above.

    Eclipse

    The Eclipse integrated development environment (IDE) is a powerful, flexible, complicated, and occasionally frustrating set of tools for writing, modifying, and debugging programs. It is especially useful for working in Java.

    When you run Eclipse, you will be prompted for a "workspace" directory, which is where Eclipse will store its configuration and metadata. On Athena, for example, the default location is a directory called workspace in your home directory. You should not run more than one copy of Eclipse at the same time with the same workspace, or the metadata will become corrupted.

    The first time you run Eclipse, it will show you a welcome screen. Click the button to go directly to the "Workbench" and you're ready to begin.

    You may also store your code in the workspace directory, but this is not required, and is occasionally confusing. On the left side of your Eclipse window is the Package Explorer, which shows you all the projects in your workspace. The Package Explorer looks like a file browser, but it is not. Don’t be fooled — it rearranges files and folders, includes things that are not files or folders, and can include projects stored anywhere on disk that have been added (but not copied into) to the workspace.

    Tab policy

    At this time you should also go through and change tabs to spaces. This will ensure that your code looks the same in all editors, regardless of the configured width of a tab character in each editor. Go to Window (Eclipse if you're running a Mac) → Preferences... In the toolbar go to Java → Code Style → Formatter. Click the "Edit..." button next to the active profile. In the new window you should change the Tab policy to "Spaces only." Keep the Indentation size and Tab size at 4. Enter a new name for the policy and press OK.

    Git

    To turn in this problem set, you will commit and push your code to a Git repository. The last code committed and pushed before the problem set due date will be used for grading.

    Git is a Version Control System (VCS). If you have used other version control software before, like SVN or CVS, many of the concepts and procedures of git will be familiar to you. The "Pro Git" book is available from the git documentation page; it describes what git is and how to use it. Quote:

    What is version control, and why should you care? Version control is a system that records changes to a file or set of files over time so that you can recall specific versions later. [...] It allows you to revert files back to a previous state, revert the entire project back to a previous state, compare changes over time, see who last modified something that might be causing a problem, who introduced an issue and when, and more. Using a VCS also generally means that if you screw things up or lose files, you can easily recover.

    Quite simplified, below are some important git concepts to know about:

    We will explain Git more deeply in a later lecture. For now, you can simply follow the instructions in this handout. If you want to go through an interactive tutorial, Code School's "Try Git" will show you these commands with a remote repository on GitHub.

    Git in 6.005 Problem Sets

    For each problem set in 6.005, we will create a git repository for you at "/afs/athena.mit.edu/course/6/6.005/git/sp13/ps[problem set number]/[your athena name].git".

    Initially this "remote" repository will contain some template code that we provide. To work on a problem set, you need to clone this remote repository into a local repository in your Eclipse workspace. To hand in your work, you need to both commit your changes to the local repository and push them to the remote repository. When the time comes for grading your assignments, we will clone the remote repository (at the location above), and look at the last commit you made and pushed there before the deadline.

    We may also occasionally publish changes to the initial starting code for a problem set. In this case we will tell you to pull from a repository at "/afs/athena.mit.edu/course/6/6.005/git/sp13/ps[problem set number]/errata.git".

    Cloning your repository

    Open the terminal and change to the directory where you would like to store your code; for example, your Eclipse workspace directory.

    If you are working on Athena, you have direct access to your remote repository over AFS. In the terminal, run

    git clone file:///afs/athena.mit.edu/course/6/6.005/git/sp13/psets/ps0/[username].git ps0

    Otherwise, you will access the remote repository over SSH. In the terminal, run (all on one line)

    git clone ssh://[username]@athena.dialup.mit.edu/afs/athena.mit.edu/course/6/6.005/git/sp13/psets/ps0/[username].git ps0
    The result should be a directory named ps0. This directory contains the starting code for the problem set. Keep the terminal open—you will need it to commit your code (you can always close your terminal and come back to the same directory to commit, of course).

    Configuring Git

    Now that you have set up your first Git repository, there are a few ways in which you should configure Git on your computer before continuing. Please follow the instructions described here to configure Git.

    Editing in Eclipse

    After cloning your repository, you need to add the project to Eclipse so you can work on it.

    1. In Eclipse, go to File → Import... → Git → Projects from Git
    2. On the "Select Repository Source" page, select Local
    3. On "Select a Git Repository," click Add..., and Browse... to the directory of your clone
    4. The "Search results" list should show your clone, with ".git" at the end; click "Finish"
    5. On "Select a wizard" for importing, choose "Import existing projects"
    6. Finally, on "Import projects," make sure ps0 is checked, and click "Finish"

    Note: if you encounter issues with Git support in Eclipse, you can import without telling Eclipse that your project is a Git repository:

    1. Go to File → Import... → General → Existing Projects into Workspace
    2. Browse... to your clone
    3. Make sure the project is checked, make sure "Copy projects into workspace" is not checked, and click "Finish"

    Turtle Graphics and the Logo Language

    Logo is a programming language created at MIT that originally was used to move a robot around in space. Turtle graphics, added to the Logo language, allows programmers to issue a series of commands to an on-screen "turtle" that moves, drawing a line as it goes. Turtle graphics have also been added to many different programming languages, including Python, where it is part of the standard library.

    We will be playing with a simple version of turtle graphics for Java that contains a restricted subset of the Logo language:

    Don’t worry about the commands to create a new window or to draw the window; those are in the actual testcases themselves, in case you’re curious. Do NOT use any turtle commands other than those listed above in your code.

    Warmup: drawSquare(), Staging, Commits, and Pushing

    Look at the source code contained in TurtleSoup.java. The first task is to implement drawSquare(Turtle turtle, int sideLength), using the two methods introduced above: forward() and turn().

    Once you've implemented the method, run the main() method in TurtleSoup.java. main() is the entry point for Java programs, and if you take a look at the source, the method simply creates a new turtle, calls your drawSquare() method, and instructs the turtle to draw. Run the method by going to Run → Run As... → Java Application in Eclipse. A window will pop up, and, once you click the "Run!" button, you should see a square get drawn.

    Committing & Pushing

    After you've finished implementing the function and verified it is correct, let's do a first commit.

    First, in the terminal, chance directory to your clone, and take a look around with

    git status

    which shows you files that have been created, deleted, and modified in the project directory. You should see TurtleSoup.java listed under "Changes not staged for commit." This means Git sees the change, but you have not (yet) asked Git to include the change as part of your next commit.

    You can run the command

    git diff

    to see your changes.

    Before committing, files must be staged for commit. Staging a file is as simple as:

    git add <filename>

    so use

    git add src/turtle/TurtleSoup.java

    to stage the file.

    In addition, it’s always a good idea to review your commits before committing to them. Run

    git status

    again to see that your changes are now listed under "Changes to be committed." If you run

    git diff

    those changes are no longer shown! Use

    git diff --staged

    to see exactly what Git will record if you commit now.

    Ready? To perform the commit,

    git commit

    will actually commit the changes locally, after opening your default editor to allow you to write a commit message (which you should always do!). Your message should be formatted according to the Git standard: a short summary that fits on one line, followed by a blank line and a longer description if necessary.

    You can use the command

    git log

    to see the history of commits in your project. Right now, you should see two of them: the initial commit to create your problem set repository with the starting code, and the commit you made just now.

    Important: only the local history has the new commit at this point; it is not stored in your remote repository. This is one important aspect where Git is different from centralized systems such as Subversion and CVS.

    In order to share the changes with your remote repository (which is the one we will be using for grading), you need to push to the remote repository, with

    git push origin

    At this point, the remote repository now has the same history as your local repository. It is important to remember that we will be grading the history in the repository on Athena; if you forget to push, we won't see your commits.

    One thing you will notice is that our infrastructure will, on commit, run a subset of the autograder on your code. Most everything will fail since you've only implemented one method, but, as the deadline approaches, this should give you feedback to make sure we can correctly compile and run your code.

    Unit Testing

    For the drawSquare() method, we used the main() method plus some visual inspection to verify that the implementation was correct. More generally, programs will have many dozens of methods that need to be tested; visually inspecting output for each one is fragile, time-consuming, and inherently non-scalable.

    Instead, we will use automated unit testing, which runs a suite of tests to automatically test whether the implementations are correct. In PS0, methods that do not draw to screen will use unit tests; we'll talk more about unit testing GUIs later in the course.

    Automated Unit Testing with JUnit

    JUnit is a widely-adopted Java unit testing library, and we will use it heavily in 6.005. A major component of the 6.005 design philosophy is to decompose problems into minimal, orthogonal units, which can be assembled into the larger modules that form the finished program. One benefit of this approach is that each unit can be tested thoroughly, independently of others, so that faults can be quickly isolated and corrected, as code is rewritten and modules are configured. Unit testing is the technique of writing tests for the smallest testable pieces of functionality, to allow for the flexible and organic evolution of complex, correct systems.

    By writing thoughtful unit tests, it is possible to verify the correctness of one's code, and to be confident that the resulting programs behave as expected. In 6.005, we will use JUnit version 4.

    The Anatomy of JUnit

    JUnit unit tests are written method by method. There is nothing special a class has to do to be used by JUnit; it only need contain methods that JUnit knows to call, which will be referred to as test methods for the remainder of the problem set. Test methods are specified entirely through annotations, which may be thought of as keywords (more specifically, they are a type of metadata), that can be attached to individual methods and classes. Though they do not themselves change the meaning of a Java program, at run-time other Java code can detect the annotations of methods and classes, and make decisions accordingly. The Java annotation system, judiciously used, can create dynamic and powerful code. Though we will not deeply explore annotations in 6.005, you will see how other libraries, such as JUnit, make effective use of them.

    Look closely at TurtleSoupTest.java, and note the @Test that precede method definitions. These are examples of annotations. The JUnit library uses these particular annotations to determine which methods to call when running unit tests. The @Test annotation denotes a test method; there can be any number in a single class. Even if one test method fails, the others will be run. The test methods can contain calls to assertEquals, which is an assertion that compares two objects against each other and fails if they are not equal, assertTrue which checks if the condition is true, and assertFalse which checks if the condition is false. Here is a list of the other assertions supported by JUnit. If an assertion in a test method fails, that test method returns immediately, and JUnit records a failure for that test.

    Running Existing Tests

    To run the tests in TurtleSoupTest, simply right click on the TurtleSoupTest.java file in either your Package Explorer, Project View, or Navigator View, and mouse-over the "Run As" option. Click on the "JUnit Test" option, and you should see the JUnit view appear, with a green bar indicating that all test methods ran successfully.

    To see what a test failure looks like, try running TurtleSoupTest.java before making any changes to TurtleSoup. You should now see a red bar in the JUnit view, and if you click on a test in the view, you will see a stack trace in the bottom box, which provides a brief explanation of what went wrong. In this case, TurtleSoup threw a RuntimeException. Double clicking on lines in the Failure Trace will bring up the code for the test that failed.

    When a test succeeds, you will see that a checkmark next to that test. Passing the public JUnit tests does not necessarily mean that your code is perfect. You should still look over the function specifications carefully and feel free to write your own JUnit tests to verify your code.

    For a more thorough introduction, O'Reilly has a JUnit and Eclipse tutorial, with screenshots to help you get acquainted with using JUnit from within Eclipse. The guide was written for JUnit 3, so the code samples use the older (but still supported) JUnit API.

    Implementing other methods

    For detailed requirements, read the specifications of each function to be implemented above its function signature in TurtleSoup.java. Be careful when dealing with mixed integer and floating point calculations. You should not change any of the method signatures (what's a signature?) below. If you do so, you risk receiving zero points on the problem set.

    Optional Challenge Problem: Implement drawSierpinskiTriangle().
    As outlined in the General Information handout, these challenge problems are completely optional and are not counted as part of the PS0 grade; however, solving enough of these challenging problems will enable you to earn an A+ grade in the course. As such, the 6.005 staff will not help or answer many questions about the challenge problems.

    Sierpinski triangle

    (Image source: Scott Sutherland, SUNY Stony Brook)

    A Sierpinski triangle is a fractal structure that can be approximated by recursively drawing triangles, among other methods. Your task is to implement a function to draw a Sierpinski triangle given the recursion depth; you should use one of the recursive algorithms, not one of the randomized ones. Furthermore, do not use algorithms that require filled/unfilled triangles; you just need to draw the lines. Finally, the length of a side is not a parameter to the algorithm; instead, implement your algorithm so that the minimum side length (in other words, the length of a side at the smallest recursion level) is distance 4. Don’t worry if, at large recursion depths, part of the triangle is off screen.

    drawSierpinskiTriangle(0) should draw a single triangle, and drawSierpinksiTriangle(1) should draw a larger triangle with 4 triangles inside. At these small sizes, you won't be able to see much if you try to draw. We will run your examples with higher recursion depths.

    Super Bonus: draw the Sierpinski triangle without retracing a single line (you may use an auxillary function).

    Submitting

    Make sure you commit AND push your changes to the repository! We will use the state of your repository on Athena as of 5:00pm on the deadline date. When you git push, the continuous build system attempts to compile your code and run a subset of the autograder tests. You can always review your build results at didit.csail.mit.edu. This feedback is provided on a best-effort basis: