Software Development (CSC 321 2016F) : EBoards
Primary: [Front Door] [Schedule] - [Academic Honesty] [Disabilities] [Email] [FAQ] [Teaching & Learning]
Sections: [Assignments] [EBoards] [Examples] [Handouts] [Outlines]
Reference: [Slack] [Ruby@CodeCademy]
Related Courses: [Rails Tutorial] [CSC 321 2016S @ EdX] [CSC 321 2015S (Davis)] [CSC 321 2016S (Rebelsky)] [CSC 322 2016F (Rebelsky)]
Misc: [SamR] [Glimmer Labs] [CS@Grinnell] [Grinnell] [Issue Tracker]
Overview
See http://www.cs.grinnell.edu/~rebelsky/s2d@g/
Write a short essay reflecting on some ethic of software engineering (e.g., ethics of software engineering as a service).
Due: Friday the 14th of October. * Free three-week extension.
Parameters
Questions
We'll continue our example from last class. What "smells wrong" in this example? (And no, don't say "The hog farm smell from this morning.")
class TimeSetter
def self.convert(d)
y = 1980
while (d > 365) do
if ((y % 400 == 0) || (y % 4 == 0) && (y % 100 != 0))
if (d > 366)
d -= 366
y += 1
end
else
d -= 365
y += 1
end
end
return [y,d]
end
end
What things don't feel right and might be a clue that we have to change something?
year += 1
class TimeSetter
BEGINNING_OF_TIME = 1980 // When Bill Gates quit Harvard
DAYS_IN_NORMAL_YEAR = 365 // Not a leap year
DAYS_IN_LEAP_YEAR = 366 // Abnormal year
def self.convert(day)
year = BEGINNING_OF_TIME
while (day > DAYS_IN_NORMAL_YEAR) do
if (isLeapYear(year))
if (day > DAYS_IN_LEAP_YEAR)
day -= DAYS_IN_LEAP_YEAR
# year += 1
else
end
else
day -= DAYS_IN_NORMAL_YEAR
# year += 1
end
year += 1
end # while
return [year,day]
end
def self.isLeapYear(year)
return (year % 400 == 0) || (year % 4 == 0) && (year % 100 != 0)
end
end
class TimeSetter // Convert the date from "days since start of time" to "current year // ..." // Pre: day is a positive integer def self.convert(day) year = START_OF_TIME while (day > numOfDaysInYear(year)) day -= numOfDaysInYear(year) year += 1 end return [year,day] end // Pre: year is an integer def self.isLeapYear(year) // According to Wikipedia, not every year divisible by 4 is a // leap year. In particular, years divisible by 100 are *not* // leap years, with the exception of years divisible by 400, // which are. // https://en.wikipedia.org/wiki/Leap_year#Algorithm return (year % 400 == 0) || (year % 4 == 0) && (year % 100 != 0) end // Pre: year is an integer def self.numOfDaysInYear(year) if (isLeapYear(year)) return DAYS_IN_LEAP_YEAR; else return DAYS_IN_NORMAL_YEAR; end end endAnother Refactoring Example
From Fields et al., _Refactoring: Ruby Edition, pp. 2-4.
class Movie REGULAR = 0 NEW_RELEASE = 1 CHILDRENS = 2 attr_reader :title attr_accessor :price_code def initialize(title, price_code) @title, @price_code = title, price_code end end class Rental attr_reader :movie, :days_rented def initialize(movie, days_rented) @movie, @days_rented = movie, days_rented end end class Customer attr_reader :name def initialize(name) @name = name @rentals = [] end def add_rental(arg) @rentals << arg end def statement total_amount, frequent_renter_points = 0, 0 result = "Rental Record for #{@name}\n" @rentals.each do |element| this_amount = 0 # determine amounts for each line case element.movie.price_code when Movie::REGULAR this_amount += 2 this_amount += (element.days_rented - 2) * 1.5 if element.days_rented > 2 when Movie::NEW_RELEASE this_amount += element.days_rented * 3 when Movie::CHILDRENS this_amount += 1.5 this_amount += (element.days_rented - 3) * 1.5 if element.days_rented > 3 end # add frequent renter points frequent_renter_points += 1 # add bonus for a two-or-more day new release rental if element.movie.price_code == Movie.NEW_RELEASE && element.days_rented > 1 frequent_renter_points += 1 end # show figures for this rental result += "\t" + element.movie.title + "\t" + this_amount.to_s + "\n" total_amount += this_amount end # add footer lines result += "Amount owed is #{total_amount}\n" result += "You earned #{frequent_renter_points} frequent renter points" result end endWhat in this code might make you worry?
Issue 1: The code for computing the cost should be moved to a separate method.
def statement total_amount, frequent_renter_points = 0, 0 result = "Rental Record for #{@name}\n" @rentals.each do |element| this_amount = 0 # add frequent renter points frequent_renter_points += 1 # add bonus for a two day new release rental if element.movie.price_code == Movie.NEW_RELEASE && element.days_rented > 1 frequent_renter_points += 1 end # show figures for this rental result += "\t" + element.movie.title + "\t" + this_amount.to_s + "\n" total_amount += this_amount end # add footer lines result += "Amount owed is #{total_amount}\n" result += "You earned #{frequent_renter_points} frequent renter points" result end def costFor(element) result = 0 # determine amounts for each line case element.movie.price_code when Movie::REGULAR result += 2 result += (element.days_rented - 2) * 1.5 if element.days_rented > 2 when Movie::NEW_RELEASE result += element.days_rented * 3 when Movie::CHILDRENS result += 1.5 result += (element.days_rented - 3) * 1.5 if element.days_rented > 3 end return result endIssue 2: Why use numbers when numbers don't make sense? Use objects or symbols.
class MovieCategory end REGULAR = new MovieCategory(...) NEW_RELEASE = new MovieCategory(...) CHILDRENS = new MovieCategory(...)
REGULAR = :REGULAR NEW_RELEASE = :NEW_RELEASE CHILDRENS = :CHILDRENS
Where should ethics of computing professionals fit within the Grinnell CS curriculum?