Design Decisions - mirkode/asana-code-challenge GitHub Wiki

Some thoughts on this app:
Please bare with me as I had to keep the developing time on this little thing quite low.

Framework

To keep it light-weight, yet having some benefits of a framework, Sinatra was chosen.
Rails for example would be way too blown up for such a little web app, so I decided that Sinatra has a perfect scope for this task.
Besides that I don't often get the chance to build something with Sinatra, so it is nice to dive into the differences from time to time.

Network

As an HTTP library I chose HTTParty over the built-in Net::HTTP library, because unfortunately Net::HTTP is way too cumbersome to use in my opinion.

Configuration

The configuration is mainly handled via ENV variables. I find this approach one of the easiest to handle as you don't need a deploy if one of those values need to change.
The dotenv gem is a nice and convenient way to include one or more configuration files (e.g. one per environment), containing all necessary info such as API keys.
Providers like Heroku make it easy to change ENV variables on the fly without fiddling with extra files.

Testing

Even though RSpec might be a little heavy for this app, I chose it mainly because tests can become very unreadable, very quickly.
So I find that RSpec and its matchers keep the spec structure nicely readable.
And my experience level with RSpec is higher than with other test frameworks, such as e.g. Minitest.
Right now there are only request specs so far (as I considered them the most important).
But one or two unit tests might follow to make sure that the provider specific responses are parsed correctly and the API output is consistent.
Maybe also some basic integration tests for the demo app will follow up.

Why jQuery?!

I would have loved to build this low-tech front-end in Vue with all the nice stuff that comes with it!
But that would have really been too much. So I decided to keep it oldschool.
Just plain and simple HTML, CSS and JavaScript/jQuery (for the ajaxy stuff).

Error handling

The API adapter has an own GeoCodingError class. It gets raised on two occasions:
Either when there are no results, or when there is a HTTP status code that is neither 200, nor 291 (so e.g. 404, 401, etc.).
In case of no results being returned, the response JSON includes the name of the provider and the error message No results..
In case of an errorneous HTTP status, the response JSON includes the HTTP status code, the request path, as well as the response from the external API.

Authorization

To start with, I included some very basic authentication. First I was thinking of JWT and such, but that would have maybe gone beyond the scope.
So, right now there is a username and password hardcoded in the demo app, which gets encoded in a base64 ASCII string. This string is then used as a token and verified on the backend side to
a.) exist
b.) match the credentials from the front-end.
In production I would probably generate a proper JWT for each app that wants to access the API and then match it against the records in the database for that particular token.