User Hierarchy
Developed with Crystal, a new language inspired by Ruby and extremely fast like C/C++ code.
Run as an API, thanks to Kemal, a powerful, simple and sinatra-like framework.
Dockerized and available on dockerhub:
docker run -p 8080:8080 gcaggia/usershierarchy:latest
To use:
curl localhost:8080/api/get-subordinates/3
File organization
- solution.cr: solution of the problem
- api.cr: web server and api to execute the code
- shard files: shard is the dependency manager for Crystal (like composer/gem/npm...)
- data folder: json files used for the problem
- spec folder: important folder to test the app. Have a look to api_spec file, it tests the app with a crystal tool similar to rspec or mochajs
- Dockerfile: my favourite file... What would be my life without Docker?
Solution of the problem
A user has a role id. To get all his subordinates, we find all the subordinates of the role of the user. Then, for each user who matches that list, we keep him.
Why working on the list of roles whereas the list of users ?
Two users can have the same role, but a role is unique.
Consequence: number_of(roles) << number_of(users).
And the complexity of the algorithm is O(roles).
Installation and use
The "Docker" approach
You will need to have docker installed on your computer.
docker run -d -p 8080:8080 gcaggia/usershierarchy:latest
Then, to see an answer following the data of the challenge, for instance user id = 3:
curl localhost:8080/api/get-subordinates/3
You can also provide your own data. For that, first, create a folder, let's call it data. Let's use the json models of users and roles. Copy them on your data local folder using curl with a redirection:
mkdir data
curl https://raw.githubusercontent.com/gcaggia/usershierarchy/master/data/users.json > data/user.json
curl https://raw.githubusercontent.com/gcaggia/usershierarchy/master/data/roles.json > data/roles.json
Now, when you start your container, map the local volume with its equivalent inside the container with a -v flag:
docker run -d -p 8080:8080 -v $(pwd)/data:/app/data gcaggia/usershierarchy:latest
It is time to play! When you change your json file, it will automatically change the response of the server. Game: let's create a complex organisation and try to crash the program!
The "hard way" approach
You will need to install crystal
brew update
brew install crystal
Then, you can clone the project
git clone https://github.com/gcaggia/usershierarchy.git
To run it, a nice way is to use two terminals or an horizontal split: one for the server, and one for the client for curl.
crystal api.cr
curl localhost:8080/api/get-subordinates/3
More information about the installation: https://crystal-lang.org/docs/installation/
Unit tests
To test the app, you will need to install it using the "hard way" method.
Then, just simply run this command:
KEMAL_ENV=test crystal spec -v
It will start a couple of automatic tests to see if everything is fine. Examples of the challenge will be test automatically.
Performance
In production, The api responds in 150 µs in average. It runs in a docker container on a small compute engine (shared cpu with 0.6 go of ram). OS is docker optimized by Google.
150 µs to get an incoming request, parse a JSON file, apply an algorithm and send a response.
This challenge was also a study to analyze the behaviour of Crystal and to compare it with other langages.