Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Naheed - Hotel - Edges #43

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open

Naheed - Hotel - Edges #43

wants to merge 16 commits into from

Conversation

arangn
Copy link

@arangn arangn commented Sep 10, 2018

Hotel

Congratulations! You're submitting your assignment!

Comprehension Questions

Question Answer
Describe a design decision you had to make when working on this project. What options were you considering? What helped you make your final decision? I decided to make an additional block_reservations class to mimic the reservations class after struggling with where to put the information for each block reservation. Looking back at what I had designed already and staying consistent with my design helped me decide on this.
Describe a concept that you gained more clarity on as you worked on this assignment. I gained much more clarity on referencing classes in my tests and was able to troubleshoot much faster when I did make mistakes
Describe a nominal test that you wrote for this assignment. A nominal test I wrote is "assigns reservation_id to reservation", which checks the new instance of reservation to ensure it has an id
Describe an edge case test that you wrote for this assignment. An edge case I wrote is "raises an Argument Error if reservation_id is not unique" to ensure that although unlikely, rand(1..100000) does not generate the same number twice
How do you feel you did in writing pseudocode first, then writing the tests and then the code? I didn't do a great job of starting with pseudocode, but I found that when I was having trouble conceptualizing a method, pseudocode and white-boarding helped.

@droberts-sea
Copy link

Hotel

What We're Looking For

Feature Feedback
Baseline
Used git regularly yes
Answer comprehension questions yes
Design
Each class is responsible for a single piece of the program some - see inline
Classes are loosely coupled mostly - see inline
Wave 1
List rooms yes
Reserve a room for a given date range yes
List reservations for a given date yes
Calculate reservation price yes
Invalid date range produces an error no
Test coverage yes
Wave 2
View available rooms for a given date range yes
Reserving a room that is not available produces an error yes
Test coverage yes, missing some edge cases, see inline
Wave 3
Create a block of rooms yes
Check if a block has rooms yes
Reserve a room from a block yes
Test coverage yes
Fundamentals
Names variables, classes and modules appropriately yes
Understanding of variable scope - local vs instance yes
Can create complex logical structures utilizing variables yes
Appropriately uses methods to break down tasks into smaller simpler tasks yes - great work!
Understands the differences between class and instance methods yes
Appropriately uses iterators and enumerables yes - see inline, but this is is a good place
Appropriately writes and utilizes classes yes
Appropriately utilizes modules as a mechanism to encapsulate functionality yes
Wrap Up
There is a refactors.txt file yes
The file provides a roadmap to future changes yes
Additional Feedback Great work overall! This code is easy to read and does a good job of solving the problem. There are a few places where the design could be cleaned up or test coverage expanded, which I've tried to call out inline below, but in general you are right where we want you to be at this point in your journey. Keep up the hard work!

class BlockReservation
attr_accessor :block_id, :reservation_id, :room, :start_date, :end_date, :price_per_night

def initialize(block_id:, reservation_id:, room:, start_date:, end_date:, price_per_night:)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only difference between this and a regular reservation is that a block reservation has a block ID. One option that might simplify your design is to consolidate both in the Reservation class, and add in an optional block ID, which would be nil if this reservation isn't part of a block.


def make_reservation(start_date, end_date)
reservation = Hotel::Reservation.new(reservation_id: generate_id, room: assign_available_room(start_date, end_date), start_date: start_date, end_date: end_date, price_per_night: 200)
@reservations << reservation

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love the way you've broken each of these bits of functionality into separate methods! However, it's a little difficult to read all on one line like this. You might split it across multiple lines:

reservation = Hotel::Reservation.new(
  reservation_id: generate_id(),
  room: assign_available_room(start_date, end_date),
  start_date: start_date,
  end_date: end_date,
  price_per_night: 200
)

I also like adding parentheses to the call to generate_id(), even though there are no arguments - this makes it a little clearer that this is a method call.

def make_block(start_date, end_date, number_of_rooms)
if number_of_rooms > 5
raise ArgumentError, "Cannot reserve more than 5 rooms"
end

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the number of rooms is less than 1?

@blocks << block

number_of_rooms.times do
block_reservation = Hotel::BlockReservation.new(block_id: id, reservation_id: nil, room: assign_available_room(start_date, end_date), start_date: start_date, end_date: end_date, price_per_night: 150)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment about line lengths on lines 36 and 40.

@reservations.each do |reservation|
if
reservation.start_date < end_date && start_date < reservation.end_date
booked_rooms << reservation.room

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here your BookingSystem is taking on some extra responsibility: determining whether a reservation overlaps a set of dates. I would argue that that is really the reservation's responsibility. You could write a method called something like Reservation#overlap?(start_date, end_date) that takes care of this logic.

That simplifies this code, and makes it easier to test the logic in isolation. You also repeat this code on line 72, which means that if the requirements change or you discover a bug, you'll have to change it in two places.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also an example of tight coupling, since BookingSystem needs to know about how a Reservation stores its dates.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not call reservations_within_date here to get the list of booked_rooms?

reservations_within_date = []
@reservations.each do |reservation|
if
reservation.start_date < end_date && start_date < reservation.end_date

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and the above method could be streamlined a little using the select enumerable:

return @reservations.select do |reservation|
  reservation.start_date < end_date && start_date < reservation.end_date
end


reservation3 = Hotel::Reservation.new(reservation_id: 3, room: @system.assign_available_room(Date.new(2018, 1, 6), Date.new(2018, 1, 9)), start_date: Date.new(2018, 1, 6), end_date: Date.new(2018, 1, 9), price_per_night: 200)
@system.reservations << reservation3
expect(reservation3.room).must_equal 2

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than creating a whole new reservation here, I would probably just call .assign_available_room and check the result directly:

room = @system.assign_available_room(Date.new(2018, 1, 6), Date.new(2018, 1, 9))
expect(room).must_equal 2

it "makes a reservation" do
@system.make_reservation(Date.new(2018,1,1), Date.new(2018,1,5))
reservation = Hotel::Reservation.new(reservation_id: 1, room: 1, start_date: Date.new(2018, 1, 1), end_date: Date.new(2018, 1, 5), price_per_night: 200)
expect(@system.reservations.length).must_equal 1

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have a lot of Date.new(...) in this file, which is a little difficult to read. Instead you might create a couple in a before block and put them in instance variables to use later:

@start_date = Date.new(2018, 1, 1)
@end_date = Date.new(2018, 1, 5)

it "raises argument error if no rooms are available" do

20.times do
reservation = Hotel::Reservation.new(reservation_id: 1, room: @system.assign_available_room((Date.new(2018, 1, 1)), (Date.new(2018, 1, 8))), start_date: Date.new(2018, 1, 1), end_date: Date.new(2018, 1, 8), price_per_night: 200)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this test case! However, it should probably be in the describe block for make_reservation, since that's what it's testing.

describe "search reservation dates" do
before do

reservation1 = Hotel::Reservation.new(reservation_id: 1, room: 1, start_date: Date.new(2018, 1, 1), end_date: Date.new(2018, 1, 8), price_per_night: 200)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are several other interesting edge cases around date overlaps that you're missing here. I see you've got the list copy-pasted below, so I'm guessing it was just a matter of time.

Putting the overlap logic into its own method on Reservation would make these tests much easier to write.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants