Friday, November 4, 2016

Berkeley CS169 - Software Engineering (Homeworks)

Once again into the breach


In the Summer of 2015 I burned though the UC Berkeley "Software Engineering" lectures, and had every intention of doing all the reading and related course work so I could "claim" it on my pseudo-transcript.  Well, here it is over a year later and I'm finally getting around to finishing it properly.  I like to think I've refined my personal process for documenting my MOOC journey (lol christ I sound like a B-school brochure)... so since I already took notes on all the coursework (see my previous post), I'll just cover the homework assignments here.



I'm certainly in a better place now, from a knowledge standpoint, than I was a year ago.  Well, at least in theory.  It's been about five months or so since I went all hog wild on Ruby and I was a bit dismayed at how much I'd forgotten in such a relatively short time... sigh.  I'm hoping I'll pick it back up quickly so I can be successful in the *current* edX course for the material, which is now called "Agile Development using Ruby on Rails".  I missed the boat on getting full credit for part 1 "The Basics", but fortunately the quizzes, videos, and (most importantly) autograders are all still up, so after binge watching the lectures for part 1 like it was Orange is the New Black, I knocked out the quizzes and got to work on the homeworks.

For easier consumption, I've consolidated all the homeworks into one super repo.  This has afforded me the unique opportunity to experiment with nested git repos... and I'll say it's a mixed bag so far.  Oh well... My SaaSbook homework repo.


Homework 0 - Intro to Ruby


I actually completed this first homework back in early spring.  I ran a "Developer Book Study" at work and convinced them to try "Engineering Software as a Service" after we finished up "Don't make me think".  I thought it had a lot of potential since learning a new programming language is more interactive than reading and discussing, and I was hoping it would give the group a much needed spark (spoiler alert... it didn't).  We got through about the second chapter and worked on the first homework (which I snagged from edX and shared side channel) during our weekly one hour meetings, but sadly, attrition and general lack of interest sunk the effort. Oh well.

The homework consists of three parts, and can be completed in less than an hour.  I worked through it collaboratively with a couple developers and system admins in this time, for what that's worth.

The homework is as much about ensuring your environment is set up right as it is about the actual code.  I will say I've been very pleased with Cloud 9 as a development platform.  While it won't work for everything (like my AI class), it's great for Ruby web apps.

Part 1 deals with operations on Arrays (the title includes Enumerables and Hashes, but I only used arrays so go figure).  We define a method to sum the elements of an array, to sum the largest two elements, and to determine if two elements exist that sum to n.  My first go (which never made it into the repo apparently), I was doing a lot of contra-Rubyist nonsense like looping through and using aggregator variables and such, before one of my proteges in the book club shared some code (which she admitted came from StackOverflow lol), that used reduce() to simplify the first two functions down to one-liners.  For the last part I implemented an algorithm I found with google, and when I white-boarded it to the group... well, it was a bit like magic haha.

Part 2 was String Manipulation and Regex.  .include?  .length  .reverse  .downcase all make appearances, as well as using /^pattern$/ =~ "matching".  Useful, but not exactly setting the world on fire.    Part 3 deals with defining a class, instance variables, and accessors, as well as a bit of validation and raising errors.  All good stuff but again, nothing to write home about.

Now, as far as recent history goes, I actually skipped over homework 1 at first because I though I had it done (from when I mucked about with this class last summer).  I got Homework 2 working then when I tried to autograde Hangman it didn't turn out quite right, so I ended up tweeking it a bit.  So lets travel back in time a year to when I first worked on it...



Homework 1 [Summer 2015]


Homework 1 has us creating a simple Hangman game using Sinatra. Sinatra is a super simple framework compared to rails (allegedly, haven’t used rails yet so I can’t really say lol). The base code includes 19 test cases for building the game logic, and turning all those red lines green was pretty fun. The HTML pages with embedded ruby, and all the forms, are already built, so other than building out the game logic class (the model), it’s just a matter of wiring up the Sinatra routes to the model. Github repo with my code. Deployed app on Heroku. I ran into a couple of "gotcha"s on this first homework:
  • before you can run autotest, you have to run "bundle"
  • if you don't commit the Gemfile, Heroku deploy will fail (will complain about "no Cedar supported app detected"

This is the first time I've used Cucumber. The code includes 12 scenarios, and they caught a couple weird behavior bugs (I hadn't caught cheating scenarios, and didn't notify player about repeated guesses).




[whoosh, it's Fall 2016 again...]

As implemented and deployed from last year, I got about 80% on the autograder.  I probably would have found the needed tweaks fairly minor if I'd bothered to read the errors more closely.  Instead I opted to make the version in my super repo work right.  Now, I'd worked through part of this homework with the book club, even passing all the rspec tests for the HangmanGame class.  But I missed all the cucumber stuff this time around, so when I deployed it to a new Heroku repo, I was a bit dismayed to find my score went from 80% to about 10%... oops.  Reason being was that the autograder only looked at the public app, which doesn't work if you don't fix the view and fill in the "app" class.  *facepalm*



Homework 2


This is the first of the "Rotten Potatoes" homeworks.  I got to rediscover the Heroku integration process, creating and deploying to a new Heroku instance.  There were other things I had to rediscover... using rake... using "rails server" with the appropriate flags so it'll work in c9... fun stuff [end sarcasm].  

The first part of the homework involved sorting movies by title or release date, and I actually had this finished already in my incomplete attempt at this homework a year ago (Summer 2015).  So that part I salvaged, which really gave me a nice boost since I was super rusty with Ruby, Rails, and the whole bit.  

Part two has us adding a little form to the page to facilitate filtering movies by rating, and in classic style I barely skimmed over the instructions and got copy-paste happy.  As a result of my haste, I missed a couple of key requirements initially... though when half the tests came back red I figured it out pretty quickly.  Mostly mundane stuff like how form elements should be identified (you'd think I'd have noticed the IMPORTANT FOR GRADING heading...)

The last part has us using the session[] to remember the state of sorting and filtering.  My first go, I did a lot of mucking around with checking and reassigning instance variables.  When this didn't pass the autograder (or the local rspec tests, can't remember which), I reread the instructions and realized I needed to make everything RESTful.  The resulting code was actually much cleaner and easier to understand.



Homework 3


This homework was surprisingly simple, and only took me a couple hours to finish.  A very gentle introduction into writing cucumber step definitions and scenarios, once I got rolling I barely had to look at the instructions, the comments in the code made the expectations very clear.  On interesting "hiccup" that started out very frustrating:

All my cukes were passing locally (in c9 anyway), but when I submitted to the edX autograder I was missing out on points.  I kept getting this weird error about "Amelie" is not found... and looking at the output, it wasn't there, but it should have been.  Digging through the discussion forums, I found someone had posted the exact same issue I was having (even the same movie), and a staff member made this comment:
Note that this grader is a MUTATION grader - it mutates the underlying app and checks that your tests fail in the correct way - does that help?
So, if the app is broken, my test should fail.  Was my test failing when it should?  I wrote a quick scenario that would fail if my "I should see all movies" step definition was correct... and it passed.  Well ok then, I have a problem.  Changed the approach I was using, got the rights tests passing and failing, and voila, full credit.  Yippee!


Homework 4


This one was a bit trickier.  The premise is that we're adding a feature to the RottenPotatoes app.  We're given three cucumber tests, but implementing the test steps, and the application changes, falls on us.  I started out with the movie_steps.rb file from the previous homework, and added to it when necessary.  I also had to add some code to the features/support/paths.rb file to account for the navigational tests.  I'm not sure if it was the intent, but I iteratively ran "cucumber" and fixed the various errors until the infrastructure was all in place... then I spent about a quarter of the time implementing the actual functionality lol.

The autograder checks for unit test coverage as part of the grade, so I had to exercise all the movie controller code, which was an experience.  Turns out if you put the controller tests in a folder called "controllers" under the spec directory, you don't have to explicitly designate it a controller test (convention over configuration for the win!).  Similarly I figured out that fixtures go under the fixtures folder (and a "yaml" file doesn't have an 'a' in the file extension... oops).  



Progress on "Part 1"


Well I finished up the first part of the homeworks (according the the latest edX version of the course.. this is "Agile Development Using Ruby on Rails - The Basics".  Sadly I couldn't get the points for the pair programming (which was half the grade for the homework) because I completed it after the end of the class.  Oh well, at least I aced the auto-graded portion:




Homework 5 (Oracle of Bacon)


This homework represented my first attempt at pair programming.  I used the Agile Ventures site and the MOOC gittr channel to coordinate.  My first foray into that realm was a bit disorganized, and we ended up getting hung up on the XML portion before I had to go (I'd been dinking around for an hour and a half at that point and the natives were getting restless).  However the second attempt was much better, and my pairing partner and I were able to work through the assignment in a very methodical way in about 40 minutes.

As far as the assignment itself, it was actually much simpler than previous assignments because there is no rails or cucumber involved, it's just rspec.  The fakes are already included as part of the scaffolding, so that was one aspect we didn't have to cope with.  The instructions include tips on working with Nokogiri (which, had I bothered to read them, would have prevented the trashing Miriam and I did on the first pairing... oops).  Sooooo yeah.... read the instructions lol.



Homework 6 (Typo - bug fix)


Once you work past all the setup and figure out how to word the cucumber test, this homework is actually super easy.  It also sort of illustrated how a bad test can send you down a rabbit hole.  I had originally started the first line of the test with "Given that I am on the new categories page", because that is the basic format followed by the "Write Articles" test.  But I kept getting an error complaining about a missing "new" method on the CategoriesController.  And sure enough there was nothing there.  But this didn't seem right, because I was supposed to be in the admin section.  What I needed was "Given that I am on the admin categories page"... then I found the bug (manifested as a "no id" exception from find), and it was a simple fix.  Tada!

On a side note, I've given up on git sub-repositories for now.  I sort of had it working for some of the earlier homeworks, but it just isn't worth the hassle.  So when I need to push to Heroku, I'm just going to reinitialize a git repo at the appropriate level and push from there, and delete it when I'm ready to commit changes to the main repo.  In a production environment you wouldn't run into this because every project would have it's own repo, it's just a bit of extra ceremony I'm willing to endure in this limited case in order to keep everything for this class in one place.



Homework 7 (Typo - article merge)


Setup was easy enough this time around (copy, paste, done!), unfortunately the severe lack of guidance in the homework instructions made this one way more frustrating than it needed to be.  We're tasked with adding a "merge" feature, to combine one article into another.  We get a picture of what it should look like ("hi-res mockup" they call it), and a couple concrete technical requirements (text box with target merge article should be named "merge_with", and the Article model should have a merge_with(id) instance method)... but that's about it.  The other requirements are more high level.

In and of itself, these aren't too serious of problems.  Where it comes into play is with the autograder.  My first pass at this, I submitted the form to another controller action (aptly named "merge").  And it worked fine on c9.  But when I submitted it, nothing worked, and I didn't get enough feedback from the autograder to figure out why not.  So I fiddled around and changed the way it works and eventually got it to work.  A few tips:

  • don't try to change the form action (using formaction="/some/route" on the submit button...)
  • use the value of param[:merge_with] to decide on if a merge action is warranted
  • don't rely on the absence of the form to ensure only admin users can merge



Homework 8


Wow, this one was so simple it hardly deserves to be considered a full blown homework.  Once we set up the project and generate the migration (all of which is set out in the instructions), there are literally two lines of code to add to create the necessary database indices.  Kind of anti-climactic honestly...



Conclusion


Wow, I feel like I've been working on this class forever.  I bombed the midterm AND the final, but apparently I did well enough on the quizzes and homework to "pass" with about a C-.  Yeesh.  But I definitely learned a lot.  I will comment that the "Open Source Homework" didn't do anything for me.  It just seemed... wrong... somehow to glom on to a bona-fide project (even a pro-bono one for charity) just for the purpose of getting a grade.  So I did the relatively easy bits (attended a scrum and created a profile) and skipped the rest.  Also skipped most of the pair programming bits because finding a decent partner was just... ugh.  Still, I'd highly recommend the course to anyone.




No comments:

Post a Comment