-
Notifications
You must be signed in to change notification settings - Fork 5
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
Popescu Alexandru Interview #4
base: main
Are you sure you want to change the base?
Conversation
7657760
to
6d5e674
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the solution. Please take the time to answer the questions. No need to do code changes.
shops_with_distances = coffee_shop_finder_service.closest_shops(lat, lon) | ||
format_response(shops_with_distances, lat, lon) | ||
rescue StandardError => e | ||
handle_error(e) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does success returns a plain/text and failure returns a json?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey! I'll answer here for 2 other comments as well to keep the conversation in one place since they're all related.
It is actually a mistake. I intended to use application/json
everywhere, but while debugging the specs for CoffeeShopController
I tried multiple approaches and forgot to roll-back this change 😅
Related comments: Why set it here as json, and override it on line 20? , Why did you choose this content type?
|
||
private | ||
|
||
# Format shops into "Name --> distance <-- (user-lat, user_lon)" strings |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this format? What's the intended audience?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The format from that comment is outdated as well, it actually returns:
Coffee shops nearest (user_lat, user_lon) by distance:
Distance <--> Name
I meant to match the __Expected output__
in a more readable format
end | ||
|
||
before do | ||
content_type :json |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why set it here as json, and override it on line 20?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
end | ||
|
||
get '/closest_shops' do | ||
content_type 'text/plain' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you choose this content type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when /Invalid CSV/ then 400 | ||
when /Failed to fetch CSV/ then 502 | ||
else 500 | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any other alternative considered? Can you share the pros and cons of different approaches?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes so I choose this approach because it was simple and fast to implement for this particular coding exercise.
It's not a scalable solution though, other better approaches I think would be:
- custom exception classes - similar to what I've done in
CoffeeShop
model class- I think this would've been the best approach since it provides type checking, it's easy to add metadata to errors and you can create some sort of logical hierarchy for errors which is also more readable. Also framework agnostic
- The drawback on speed ( initial class setup ) is minimal
- using a framework-specific handling
- Biggest con is that I'm not familiar with Sinatra
def handle_error(error) | ||
status_code = case error.message | ||
when /Invalid CSV/ then 400 | ||
when /Failed to fetch CSV/ then 502 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
502 is not correct here according to industry standards: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/502
"The HTTP 502 Bad Gateway server error response status code indicates that a server was acting as a gateway or proxy and that it received an invalid response from the upstream server. This response is similar to a 500 Internal Server Error response in the sense that it is a generic "catch-call" for server errors."
Our server does not act as a gateway or proxy, although it requests another server. In our case, the remote CSV acts as a database
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with you. I treated the remote CSV as another server, so 502
made sense in my head, but if it mimics our said DB, code 500
would make more sense 🧠
# Handle errors with appropriate HTTP status codes | ||
def handle_error(error) | ||
status_code = case error.message | ||
when /Invalid CSV/ then 400 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
400 is not correct here according to industry standards: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400.
"The HTTP 400 Bad Request client error response status code indicates that the server would not process the request due to something the server considered to be a client error. The reason for a 400 response is typically due to malformed request syntax, invalid request message framing, or deceptive request routing.
Clients that receive a 400 response should expect that repeating the request without modification will fail with the same error."
It's not requester fault that the server's data is invalid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The requester may not modify the request and stop receiving 400 at later times
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea correct this is a mistake. The fact that our DB data is invalid is not on the client side.
I should've use code 500
or 422 Unprocessable Content - "status code indicates that the server understood the content type of the request content, and the syntax of the request content was correct, but it was unable to process the contained instructions."
Float(str) | ||
end | ||
|
||
# Handle errors with appropriate HTTP status codes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment doesn't tell more than what the code tells. Comments have a specific purpose throughout the code. You can check this paper for when comments might be a good idea: https://stackoverflow.blog/2021/12/23/best-practices-for-writing-code-comments/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be deleted as well: # Validate CSV row structure 🗑️
Instructions
Provided Coding challange description
Overview
You have been hired by a company that builds a app for coffee addicts. You are
responsible for taking the user’s location and returning a list of the three closest coffee shops.
Starting point
Fork or clone our ruby starter project: https://github.com/Agilefreaks/ruby-interview-starting-point
Input
The coffee shop list is a comma separated file with rows of the following form:
Name,Y Coordinate,X Coordinate
The quality of data in this list of coffee shops may vary. Malformed entries should cause the
program to exit appropriately.
Notice that the data file will be read from an network location
(ex: https://raw.githubusercontent.com/Agilefreaks/test_oop/master/coffee_shops.csv)
Output
Write a REST API in any framework you wish (excluding Rails) that offers the posibility to take the user's coordinates and
return a list of the three closest coffee shops (including distance from the user) in
order of closest to farthest. These distances should be rounded to four decimal places.
Assume all coordinates lie on a plane.
Example
Using the coffee_shops.csv
Input
47.6 -122.4
Expected output