Wednesday, July 31, 2013

Building Classes from Scratch Based on Known Inputs and Desired Outputs

Today I had the privilege to undertake a challenge on Udacity.com's Introduction to Programming course that was extremely well designed to put my knowledge and abilities of Classes to the test.  The challenge was optional, however I was determined to stretch my knowledge in order to deepen my understanding, as well as intuit ways to solve OOD problems.

The problem was loosely stated as follows:
The program would take in as input a "story" of a photography company's business processes.  Namely, these processes consisted of:
  • Hiring new photographers
  • Taking in new assignments from clients
  • Allocating photographers for each assignment
  • Reviewing the portfolio of the company's work
The "story" took on the format as follows:
Photographer Danny //hire a new photographer named "Danny"
Photographer Leslie
5 a parrot //top priority assignment to take a photo of a parrot
2 a waterfall
4 a mountain
3 Paris
GiveOutAssignments //assign each photographer with 1 assignment, 
4 a pony           //top priority first
GiveOutAssignments
GiveOutAssignments
1 the forest
2 a flower shop
GiveOutAssignments
3 a butterfly
4 a sprout in the rain
GiveOutAssignments //after the last line, review portfolio

Udacity gave some "cheat" code that read in the file, parsed, and provided the following information:
  • For "hire new photographer" lines, the following code is executed:
    • manager.hire(photographer)
    • i.e. the "hire" method is called on an instance of the Manager Class passing the parameter "photographer" of type String
  • For "new assignment" lines, the following code is executed:
    • manager.newAssignment(priority, description)
    • i.e. the "newAssignment" method is called on an instance of the Manager Class passing the parameters "priority" of type int and "description" of type String
  • For "give out assignments" lines, the following code is executed:
    • manager.giveOutAssignments()
    • i.e. the "giveOutAssignments" method is called on an instance of the Manager Class
  • When the end of the "story" file is reached, the following code is executed:
    • manager.reviewPortfolio()
    • i.e. the "reviewPortfolio" method is called on an instance of the Manager Class
Other than the code necessary to parse the file and call methods of an instance of Manager "manager" which was contained within a Class called Simulation which contained the "main" method, the construction of the rest of the solution was left up to the students.

My approach can be summarized as follows:
  1. Determine the tasks involved in the solution
  2. Flesh out the inner-workings of those tasks
    1. Determine other Classes that could assist in the solution
    2. Determine instance variables that would also be necessary
    3. Loosely consider the public methods that would be required to exchange information between classes
  3. Start writing methods for each task
    1. Write accessor methods to other Classes as if those methods already existed
    2. Keep a list of accessor methods required to implement in other Classes.
  4. Debug
  5. Test
In detail, my method went as follows:
1) Determine the tasks involved in the solution:
  • hire photographer
  • create assignments
  • give out assignments
  • display portfolio
Already I had a keen sense that I would require the following helper Classes at minimum:
  • Photographer (would contain the photographer's name, "take pictures")
  • Assignment (would contain the assignment's priority, along with description)
  • Portfolio (would contain the pictures taken by all photographers)
2) Flesh out the inner-workings of those tasks:

Hire photographer:
  • needs to create a new Photographer object (pass String "name" to Photographer's Constructor
  • Manager Class would contain an ArrayList of Photographers, add() Photographer
  • Photographer Class would have a Constructor that passes the "name" to the Photographer object
Create Assignments:
  • needs to create a new Assignment object (pass int "priority" and String "description to Assignment's Constructor)
  • Manager Class would contain an ArrayList of Assignments, add() Assignment
  • Assignment Class would have a Constructor that passes the "priority" and "description" to the Assignment object
  • In order to ease the "pain" of keeping track of where the highest priority Assignments are in the assignments ArrayList, each new Assignment will be added by descending priority
Give out assignments:
  • For each Photographer, give out the next highest priority Assignment (first item in sorted ArrayList)
    • Do this by calling Photographer's "take photo" method
    • Pass photo to Portfolio, along with the photographer's name
Display portfolio:
  • Call the portfolio's draw method
At this point I got a sense that the Portfolio Class would contain an ArrayList of Pictures.  More specifically, I would want those Pictures to have the photographer's name displayed along with the picture.  From this, I gleaned that I would require another Class I would dub FinishedPhoto, which would contain both a Picture and Text object containing the photo and the photographer's name, respectively.

3. Start writing methods for each task:

As already included in the summary, I went about this by first constructing the various Constructors of my Manager and helper Classes, followed by fleshing out the methods of the Manager class.  I kept my perspective completely locked on the Manager Class while writing Manager methods, assuming I had complete access to the other helper classes via methods that I assumed were already fully implemented. 

After completing each Manager method, I would review the code to determine which public methods I needed to write for my various helper methods which I wrote on a piece of paper.  After writing all of those down, I switched my focus over to the helper Classes and wrote the methods that the Manager Class would need for the Manager methods, fleshing out instance variables as needed along the way.

Rinse and repeat until I implemented all of the Manager Class methods, along with the corresponding helper Class methods.  I made some anticipated syntax mistakes that threw the compiler for a loop, however I was very pleased when the test case passed on the first try!  See my completed code here.

Saturday, July 27, 2013

Refactoring: Variable Renaming Approach and Methods

Recently I watched a segment from Udacity.com's Introduction to Programming course that focused on the software development term "refactoring".  Refactoring is the process of updating existing code in order to make that code more efficient, more readable, more compatible with new technologies, and many more reasons.  This concept was also recently addressed at a Geekfest meetup by Chris Powers on the refactoring of Javascript (Speaker Deck slides available here).

As an introduction to this concept, let's consider the following code:

String[] array = {Joe, Sam, Dave, Charley};
int end = array.length;
for (int i = 0, i < end; i++)
{
    array[i] = "Mr. " + array[i];
}

From reading this code, we come to the understanding that an array of String objects are each concatenated with the String "Mr. ".  Although that is fairly clear, our variable names do not help a programmer understand the object's purpose (i.e. "array", although good at describing that the object is an array, does not do very well to expound on the fact that this is an array of String objects, much less that the String objects are all names of (presumably) men.  We therefore have a good opportunity to refactor this code in order to rename more sensical variables.

From Udacity's course, there are a couple of approaches to refactoring variable names.

  • Create test cases with expected results prior to refactoring code
  • Fully implement refactored variable names BEFORE removing any current code
Creating test cases for the above code is fairly simple:

for (String name : array)
{
    System.out.print(name + ", ");
}
println();
System.out.println("Expected result: Mr. Joe, Mr. Sam, Mr. Dave, Mr. Charley");
The above code will suffice in printing the contents of array after the for loop completes execution.  Now we are ready to refactor the code.

Per the above example, we would like to rename "array" to a more appropriate name that will denote that the contents of the variable.  Therefore, instead of

String[] array = {Joe, Sam, Dave, Charley);

the more descriptive

String[] arrayOfMaleNames = {Joe, Sam, Dave, Charley);

will be more readable for future programmers who come upon this code.  Before removing the old representation of array, per Udacity's approach and method, we should find all representations of array throughout the current code prior to removing.  Therefore, we get

 String[] array = {Joe, Sam, Dave, Charley};
 String[] arrayOfMaleNames = {Joe, Sam, Dave, Charley};
int end = array.length;
int end = arrayOfMaleNames.length;
for (int i = 0, i < end; i++)
{
    array[i] = "Mr. " + array[i];
    arrayOfMaleNames[i] = "Mr. " + arrayOfMaleNames[i];
}

This modification must also be made to our tester


for (String name : array)
for (String name : arrayOfMaleNames)
{
    System.out.print(name + ", ");
}
println();
System.out.println("Expected result: Mr. Joe, Mr. Sam, Mr. Dave, Mr. Charley");

Now that the modification has is ubiquitous, we are ready to remove all instances of array, yielding:


//Main code
String[] arrayOfMaleNames = {Joe, Sam, Dave, Charley};
int end = arrayOfMaleNames.length;
for (int i = 0, i < end; i++)
{
    arrayOfMaleNames[i] = "Mr. " + arrayOfMaleNames[i];
}


//tester
for (String name : arrayOfMaleNames)
{
    System.out.print(name + ", ");
}
println();
System.out.println("Expected result: Mr. Joe, Mr. Sam, Mr. Dave, Mr. Charley");

Next, we will modify the for loop.  Because all indexes in the array will be accessed, there is no use in creating a separate index to go through all of the array values.  This would be a different case if the array had been instantiated with, say, 100 indexes of which only the first 4 were utilized.  Instead, since the array is fully implemented with the four strings "Joe, Sam, Dave, Charley" for the array's four indexes, we are ok implementing the for loop as follows:

int end = arrayOfMaleNames.length;
for (int i = 0, i < end; i++)
{
    arrayOfMaleNames[i] = "Mr. " + arrayOfMaleNames[i];
}
for (String name : arrayOfMaleNames)
{
    name = "Mr. " + name;
}

After writing the refactored for loop we are ready to remove the old code, yielding:

//Main code
String[] arrayOfMaleNames = {Joe, Sam, Dave, Charley};
for (String name : arrayOfMaleNames)
{
    name = "Mr. " + name;
}


//tester
for (String name : arrayOfMaleNames)
{
    System.out.print(name + ", ");
}
println();
System.out.println("Expected result: Mr. Joe, Mr. Sam, Mr. Dave, Mr. Charley");

Finally, we still have a 'magic' String "Mr. " to deal with.  This is considered a 'magic' String, or object in general, because there is no precedence for why this particular String was chosen, and if it exists in several places throughout the code, it could be very tedious to replace (what if instead of "Mr. " we wanted to implement "Dr. " for example?).  It is better to declare this value in a separate variable, then replace the 'magic' String with that variable.  After writing our refactored code:


String[] arrayOfMaleNames = {Joe, Sam, Dave, Charley};
String abbreviation = "Mr. ";
for (String name : arrayOfMaleNames)
{
    name = "Mr. " + name;
    name = abbreviation + name;
}

Removing the old code yields:


//Main code
String[] arrayOfMaleNames = {Joe, Sam, Dave, Charley};
String abbreviation = "Mr. ";
for (String name : arrayOfMaleNames)
{
    name = abbreviation + name;
}


//tester
for (String name : arrayOfMaleNames)
{
    System.out.print(name + ", ");
}
println();
System.out.println("Expected result: Mr. Joe, Mr. Sam, Mr. Dave, Mr. Charley");

After comparing the test result prior to refactoring to the result after refactoring, we see that the results are the same, and our refactoring is complete (for now)!



Monday, July 22, 2013

Novel Approach to Nested Loops

Yesterday my Udacity.com Introduction to Programming course introduced the following nested loop problem:

Write a nested-loop that creates a triangle pattern based on the number of rows input by the user such that the nth row has n ASCII-art boxes.
Examples: 
 if n = 1
[]
if n = 3
[]
[][]
[][][]
if n = 8
[]
[][]
[][][]
[][][][]
[][][][][]
[][][][][][]
[][][][][][][]
[][][][][][][][]

My initial approach to this problem was that it would be fairly easy to keep track of each row, however the number of "[]" would be less simple to track due to their inflating nature by row.  Since the number of "[]" per row would be dependent upon row number, I chose to implement a while loop that compared some integer i counting up from 0 until it reached the given row as dictated by a for loop, seen below:

for (int row = 1; row <= userInput; row++)
{
    int i = 1;
    while (i <= row)
    {
        System.out.print("[]");
    }
    System.out.println();
}

While the above code works, the solution provided by the professor took me as more elegant, and the approach the professor used was far more intuitive as well.  The summary of the approach is as follows:


  1. Determine the for loop solution to writing the first row of "[]"
  2. Determine the for loop solution to writing the second row of "[]"
  3. Intuit from the similarity/dissimilarity of the for loops from 1 & 2 the nested for loop solution
  4. Write the code necessary for the final solution
The above approach applies to the stated triangle pattern problem as follows:


  1. for (int i = 1; i <= 1; i++) { System.out.print("[]") } //code necessary to print row 1
  2. for (int i = 1; i <= 2; i++) { System.out.print("[]") } //code necessary to print row 2
  3. The only difference between 1 & 2 is the comparison expression of the for loop.  The intuition is that the non-i value of the comparison expression can be replaced by the row value.  Therefore the solution involves replacing the comparison terminating value with row and nesting the above loop in another for loop that steps through all of the possible values of row.
  4.  
for (int row = 1; row <= userInput; row++)

{
    for (int i=1; i <= row; i++)
    {
        System.out.print("[]");
    }
    System.out.println();
}


I am certain this approach will provide a more cohesive and logical approach to determining correct and efficient nested for loop solutions in the future.

Sunday, July 21, 2013

Day 0: Checking in, Status

"Today is the first day of the rest of your life..."

As an EE with a specialization in digital design, I was somewhat familiar with the principals of programming on a very small sense given that HDLs like VHDL and Verilog were part of my college curriculum.  However nothing could have prepared me for the enjoyment I would soon experience as I entered my first role out of college with Cisco Systems as an ASIC Design and Verification engineer.  Although my old friend Verilog was there with me at the onset, part of my role had me verifying my colleagues and my own work with a proprietary C++ environment.  This was my first taste of programming in a purer form, and one in which I became increasingly interested in developing my skills and abilities.

This interest took a three year hiatus as I moved to Columbus, Ohio to pursue my now-wife, Emily.  As thrilling and enriching an experience as that was, my employment over that period focused purely on hardware development in my new role at Honda Research & Development.  When my wife landed a great opportunity in her career as a dentist in Chicago, IL, I knew that my opportunity to delve deeply into the world of CS and programming had finally come.

So here I am today!

No longer working for Honda Research and Development, I will be devoting myself fully to my self initialized and led education into the world of programming and development with the final goal to master the skills and arts necessary to the extent necessary to land a role in the blooming tech-scene of Chicago.

What I have done so far:

  • Initialized classwork on Udacity.com
    • Introduction to CS (~45% complete)
    • Introduction to Programming (~65% complete)
    • Algorithms (~10% complete)
  • Begun networking in Chicago
    • Attended TechWeek Chicago 2013
    • Attended Udacity.com 2nd Annual Global Meetup
  • Combed the work opportunities in Chicago
    • Learned the various technologies implemented by companies in Chicago
      • ASP.NET
      • Mobile Technologies
      • Java
      • Front-end (HTML, CSS, JavaScript)
      • C#
    • Learned the location of technology companies around Chicago

What I have planned to do:

  • Continue Udacity.com coursework
    • Complete Introduction to CS
    • Complete Introduction to Programming
    • Complete Algorithms
    • Start Software Testing
    • Start Software Debugging
    • Start Programming Languages
    • Start Web Development
    • Start Introduction to Theoretical Computer Science
  • Start "Hello, Android!"
    • A re-start of sorts, get through the book "Hello, Android!"
  • Start "Chooser" Android App
    • Flesh out the idea for "Chooser"
    • Develop the application for Android utilizing the knowledge learned from "Hello, Android!"
    • Determine if it is possible to publish the app
    • If possible to publish: publish, then learn how to roll out an application update
This will be an interesting adventure, and I am glad to have the opportunity to be on it!

Twitter: @shiggiddie
Google Calendar: sean.dennison.osu@gmail.com