This is the take-home project for engineers at Lovevery, and thanks in advance for taking the time on this. The goal of this project is to try to simulate some real-world work you'll do as an engineer for us, so that we can see you write some code from the comfort of your own computer.
The basic flow is:
- Visit
/
and see the products - Select a product to view it or click directly on the Give Gift button
- Inside of the product you will also be able to click on Give Gift
- Fill in the data needed to give a gift away:
- Gifter Information
- First Name
- Last Name
- Child's Information
- Full Name
- Birthdate
- Parent Name
- Credit Card Information
- Card Number
- Expiration Month
- Expiration Year
- Message
- An optional text to be attach to the gift.
- Gifter Information
- Click purchase gift to give away that product.
- This will create an order in our system, it will find or create a new gifter and lastly it will create a gift record in our database.
- Child MUST already exist on our system.
- This means that an ORDER must had been purchased in the past with the child's information.
- Full name, Birthdate and Parent Name values must strictly match the ones in our system.
- Address and Zipcode are obtained from Child's last registered order.
- Credit Card information must be valid.
Assuming you have Ruby installed and are using a Ruby version manager like rvm or rbenv, you should be able to:
> bin/setup
> bin/rspec
This should install needed gems, set up your databases, and then run the tests, which should all be green and pass.
Run the following command to spin up the server:
> rails server
Then go to your browser: localhost:3000
and the app should be up and running.
https://lovevery-app.herokuapp.com/
I followed a TDD approach to overcome and tackle this Gift feature.
I created 3 new models (Gift, Gifter and OderGift).
- Gifter => It holds all the person's data providing the gift.
- Gift => It is the model's main feature because it wires everything up between [Gifter, Product, Child and Order].
- OrderGift => It is responsible for associating the order with a gift.
- An order can have many gifts but a single gift can only have one order => Solid idea on how I approached this feature :D .
You will also find a couple of services that are in charge of very specific responsibility from the bussiness logic.
- SearchChildService => Responsible of finding a child base on their full name, birthdate and parent name.
- SearchGifterService => Responsible of finding or creating a gifter.
- CreateOrderService => Responsible of creating the order and calling the Purchase service.
- BuildGiftService => Responsible of Orchestrating all the above services. It also returns a gift instance to the controller so it can be save in our system.
- They all contain a single public interface method
call
. - They focus on a specific task from the bussines logic.
- They return either
failure
orsuccess
. If it is asuccess
then it should return the properinstance object
to be save/update in database. To follow this pattern strategy I created 2 POROs (Plain Old Ruby Objects)Success
andFailure
to encapsulate custom exceptions and responses from each service object. Additionally, I opted to delegate theExceptions handling
responsibility toApplicationController
because it's the common place where all controllers inherit from, and a centralize place to catch each exception and render them.
You will find must all of the new models, controllers and services to have tests around their functionalities and edge cases.
Each Model, Service and Controller will have their proper xxxx_spec.rb
file.
I also apply factories
to be able to mock model data and build the testing proper scenarios.