|
| 1 | +# Workana Hiring challenge |
| 2 | + |
| 3 | +Hi! |
| 4 | + |
| 5 | +We are looking for great PHP and Javascript developers to join our team. |
| 6 | +Instead of going through a ~~boring~~ long interview process, we decided that code often speaks for itself. |
| 7 | +If you're up to the challenge, please take a couple of hours to play with this challenge and submit your solution. |
| 8 | + |
| 9 | +## The Planning Poker Lobby |
| 10 | + |
| 11 | +[](https://codepen.io/emilioastarita/pen/NWRKWwv) |
| 12 | + |
| 13 | +This time let's build a little [planning poker](https://en.wikipedia.org/wiki/Planning_poker) system. The exercise |
| 14 | +will work in multiple levels (while you're |
| 15 | +not supposed to work on all of them we hope that you can handle at least one with a good level of expertise). |
| 16 | + |
| 17 | +### At backend layer you can choose among three options: |
| 18 | + |
| 19 | +- **Mocked Service** mock your responses in the client side using async functions (use this option if you are front developer) |
| 20 | +- **Node Js Backend** Here you can use express, implement your own server or any framework of your preference. If you go with this option |
| 21 | +we expect to see more realtime features. |
| 22 | +- **PHP Server** If you go with PHP please pick a light framework. We expect to see more enterprise level software with robust error handling at API level. |
| 23 | +Bonus if you use PHP 8 features. |
| 24 | + |
| 25 | + |
| 26 | +### Backend endpoints to implement |
| 27 | + |
| 28 | +Let's build a REST API with the following endpoints. Feel free to change some things these |
| 29 | +descriptions are only for guidance. |
| 30 | + |
| 31 | +##### `POST /issue/{:issue}/join` - Used to join `{:issue}`. |
| 32 | + - If issue not exists generate a new one. |
| 33 | + - Must receive a payload with the intended name. ie: `{"name": "florencia"}` |
| 34 | + - Feel free to use a session or token to keep identified the user in subsequent requests. |
| 35 | + |
| 36 | +##### `POST /issue/{:issue}/vote` - Used to vote `{:issue}`. Must receive a payload with the vote value. |
| 37 | + - Reject votes when status of `{:issue}` is not `voting`. |
| 38 | + - Reject votes if user not joined `{:issue}`. |
| 39 | + - Reject votes if user already `voted` or `passed`. |
| 40 | + |
| 41 | +##### `GET /issue/{:issue}` - Returns the status of issue |
| 42 | + Because during `voting` status the votes are secret you must hide each vote until all members voted. |
| 43 | + - Issue is `voting`: |
| 44 | + ````json |
| 45 | + { |
| 46 | + "status": "voting", |
| 47 | + "members": [ |
| 48 | + {"name": "florencia", "status": "voted"}, |
| 49 | + {"name": "kut", "status": "waiting"}, |
| 50 | + {"name": "lucho", "status": "passed"} |
| 51 | + ] |
| 52 | + } |
| 53 | + ```` |
| 54 | + - Issue is `reveal` when all users emitted their votes: |
| 55 | + ````json |
| 56 | + { |
| 57 | + "status": "reveal", |
| 58 | + "members": [ |
| 59 | + {"name": "florencia", "status": "voted", "value": 20}, |
| 60 | + {"name": "kut", "status": "voted", "value": 20}, |
| 61 | + {"name": "lucho", "status": "passed"} |
| 62 | + ], |
| 63 | + "avg": 20 |
| 64 | + } |
| 65 | + ```` |
| 66 | +
|
| 67 | +#### Realtime |
| 68 | +
|
| 69 | +If you are implementing backend with node could be nice to have a collection of events notifying clients about new votes |
| 70 | +and changes using some kind of realtime technology of your choice as websockets or long-polling. |
| 71 | +
|
| 72 | +#### Persistence |
| 73 | +
|
| 74 | +For persistence use the `redis` service provided in docker-compose and choose the best combination of operation/data structures |
| 75 | +that serves for your solution. |
| 76 | +
|
| 77 | +If you don't want to mess too much with the backend, and you are in the node path you can use `in memmory` persistence but please |
| 78 | +provide some kind of abstraction around your store. |
| 79 | +
|
| 80 | +
|
| 81 | +**Bonus points** if you can provide some hints around horizontal scalability of the backend service using `redis` features. |
| 82 | +
|
| 83 | +
|
| 84 | +### Frontend |
| 85 | +
|
| 86 | +Provide an interface to use the system. |
| 87 | +
|
| 88 | +
|
| 89 | +If you are backend developer and don't want to build a front give us a bunch of `curl`s showing how to query |
| 90 | +the status and how to do some votes. |
| 91 | +
|
| 92 | +If you want to work on frontend use Vue 2 or Vue 3 to construct an interface: |
| 93 | +
|
| 94 | + - Take a look at [our Codepen](https://codepen.io/emilioastarita/pen/NWRKWwv) if you are looking for some inspiration or ideas. |
| 95 | + - Create or join an issue by number |
| 96 | + - Show board with cards for voting |
| 97 | + - Show a list of members and the status of each one |
| 98 | + - Allow users to vote, pass or leave the issue |
| 99 | + - Bonus points if you handle client side routing (you can use libs) |
| 100 | +
|
| 101 | +If you prefer to work only on front side no problem! Just fake the data using a bunch of async local functions and handle |
| 102 | +a global state holding your data at the root component. |
| 103 | +
|
| 104 | +```javascript |
| 105 | +async function getMembers() { |
| 106 | + return [ |
| 107 | + {"name": "florencia", "status": "voted", "value": 20}, |
| 108 | + {"name": "kut", "status": "voted", "value": 20}, |
| 109 | + {"name": "lucho", "status": "passed"} |
| 110 | + ]; |
| 111 | +} |
| 112 | +``` |
| 113 | + |
| 114 | +We are interested to know how you work and if you are able to produce quality code, so take some time to think around |
| 115 | +details and put some effort to treat errors with robustness. |
| 116 | +Feel free to guide us to review your code and explain where you put more effort |
| 117 | +or what you were thinking when you take the key design decisions. |
| 118 | +
|
| 119 | +#### Some considerations: |
| 120 | + - The demo is in a single component, but it's better if you can use many, and demonstrate how would you communicate between them. "Divide and Conquer" :muscle: |
| 121 | + - Try to use good conventions and semantically correct names for variables & functions. |
| 122 | + - Take advantage of vue reactivity with computed properties and its two-way data-binding :twisted_rightwards_arrows: |
| 123 | +
|
| 124 | +## Get up and running |
| 125 | +
|
| 126 | +To run this code you need: |
| 127 | + - [Docker](https://www.docker.com/get-started) and [docker-compose](https://docs.docker.com/compose/install/) installed |
| 128 | +
|
| 129 | +Then: |
| 130 | + - Clone this repo: `git clone [email protected]:Workana/hiring_challenge.git`. |
| 131 | + - Run `docker-compose up`. |
| 132 | + |
| 133 | +Check if services are up and running: |
| 134 | + - Node backend in [localhost:8082](http://localhost:8082/issue/234) |
| 135 | + - PHP backend in [localhost:8081](http://localhost:8081/issue/234) |
| 136 | + - Front dev server with demo in [localhost:8080](http://localhost:8080/) |
| 137 | +
|
| 138 | +
|
| 139 | +## What we would like you to do? |
| 140 | +
|
| 141 | +Download this repo. Code it your way. Choose what parts of the system you want to implement and put your best effort doing it. |
| 142 | +
|
| 143 | +- Some unit testing is mandatory. |
| 144 | +- Although we love other languages too, we prefer if you stick to PHP, Javascript or Typescript, as these are |
| 145 | +Workana main languages. |
| 146 | +
|
| 147 | +
|
| 148 | +
|
| 149 | +## Submission |
| 150 | +
|
| 151 | + Please don't submit Pull Requests. After you're done, please email to [[email protected]](mailto:[email protected]) |
| 152 | + with the link to your fork, so we can start talking =) |
| 153 | +
|
| 154 | +Thanks a lot and happy coding! |
| 155 | +
|
0 commit comments