Welcome!
This repository contains the Uplift coding challenge. We believe in letting you work as freely as you want within the constraints of the project. Our goals are to assess:
- your ability to follow specs/requirement docs, making pragmatic decisions along the way
- your level of expertise (mid-level=good approach, expert level=teach us something we don't know)
- Evaluation criteria
- General instructions
- Docker setup
- Using make
- Frontend challenge
- Backend challenge: Python
- Backend challenge: NodeJS
- Backend challenge: PHP
- Full Stack challenge: Python & React
- License and sharing
- overall architecture and code quality (readability, decoupledness, etc)
- file structure
- naming (variables, files, etc)
- test coverage (see instructions for running tests)
- proficiency at languages and libraries chosen for the task
If you wish to work full-stack, please attempt both frontend and backend in separate Pull Requests. Submit a PR first with your most comfortable or desired choice, so we can offer you feedback sooner.
- Please note there is a shared
.env
file for environment variables. This file is used by both the frontend and backend. - Please lint and explain your code (even just briefly). CI runs checks, you can see them in
.github/workflows
- After completing the challenge to a level that you're satisfied shows off your expertise, open a pull request against master (open two separate ones if you're doing frontend + backend)
- In your PR, add a description explaining your approach and anything else you think is worthwhile. Screenshots and demo videos are encouraged!
- The repo uses CI to lint and run tests on your PR. We'd like to see those passing.
We think it's easier to complete the challenge using Docker. If you are familiar with Docker and already have it installed, you can skip to the specific challenge you are doing. Otherwise, below are some instructions on how to get Docker installed on your system.
Linux
-
Install
sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
-
Verify
sudo docker run hello-world
This should pull the image, run the container, print the message and exit.
-
Add your user to the
docker
groupsudo groupadd docker sudo usermod -aG docker $USER newgrp docker docker run hello-world # now the test should run without sudo
For more information, check the Docker docs.
MacOS
-
Install Docker with brew
brew install --cask docker brew install docker-compose
-
Verify
docker --version
If this does not display the Docker version, you should restart the Docker deamon. You can find it using Spotlight or under the Applications folder.
For more information, check the Docker docs and this guide.
Windows
Docker offers an installer for Windows. Please check the Docker docs and, if you need additional information, this guide from Microsoft. Both guides use WSL 2.
To make the development flow easier, we've added a Makefile with many useful targets. Check this guide for more information on how to use make
.
- To list all available commands, either check the file or run
make help
. - If you want to pass additional arguments, for commands that allow this, you'll have to do the following:
make target-name ARGS='<any arguments>'
. For example, if you want to detach a container when running it, you'll have to do:make python-start ARGS='--detach'
.
Use React, TypeScript, and Tailwind.
Feel free to use any additional libraries, except for out-of-the-box deck/card dealing.
Please write tests.
The task is to build a simple card game. The designs are in Figma, you can see desktop and mobile pages. The fonts should be available in Google Fonts, but we also included them in assets if they ever take them down (has happened before). It doesn't have to be pixel perfect, but it should look nice.
Requirements
- Assuming a standard deck (52 cards of 4 suits: ♣ Clubs, ♦ Diamonds, ♥ Hearts, ♠ Spades).
- Press a "Deal" button to deal 5 random cards.
- Pressing the button again should deal 5 unique, random cards. Within the same game, you should never get the same cards again that you got in the past (just like a physical deck).
- Add a card counter which shows how many cards are left.
- Add an ace counter which shows how many aces are left. (this is not present in the designs at the time of this writing, you can do it the way it makes most sense to you, consistent with the designs)
- Add a button to reset the game.
- When all the aces have been dealt, "Game Over" should be displayed.
- If there is an ace in the last draw and there are no more cards left to deal, display "Winner", otherwise display "You Lose. Better luck next time!" Last draw means the last draw that is allowed, as there could be additional cards left to deal, but no aces.
Bonus!
- Animations. Wow us!
- Sounds
- Deploy to the web for us to play
Here are some demos, to paint a picture of submissions for candidates we've hired. You don't have to match these exactly.
If you have any issues with husky/commit hooks, you may remove the *.py section of "lint-staged" in package.json
Additionally, if you're on Windows, check out this tip for yarn with husky on Windows.
- Node 12+ (tested on 12.3.1)
- Yarn 1+ (tested on 1.16.0)
CI runs prettier and eslint. Configuring your editor/IDE appropriately will make it easier for you to ensure passing CI tests when you submit.
make frontend-start
yarn install
# then
yarn start
Your browser will automatically open to http://localhost:3000 by Create React App. Changes should be reflected automatically.
See CRA documentation.
You are welcome to use Next.js instead, we just set up CRA for convenience.
TL;DR (but please, read on): backend version of the frontend card game. Use Django (v3+), graphene (v2), and a PostgreSQL database.
You should implement your own database architecture (models) and your own GraphQL schema.
There's no requirement to implement authentication. You can fake it at the middleware level, or log in to the Django admin and send subsequent requests with the session information set by Django. However, clean implementations of session/auth/login earn bonus points!
Requirements
- Assuming a standard deck (52 cards of 4 suits: ♣ Clubs, ♦ Diamonds, ♥ Hearts, ♠ Spades).
- GraphQL mutation to deal 5 unique, random cards (or fewer if there aren't 5 left).
- Within the same game, you should never get the same cards again that you got in the past (just like a physical deck).
- Game is over when all Aces have been dealt. If this happens in the final hand, the user Wins; otherwise, the user loses.
- The GraphQL API should provide access to,
- Remaining card count
- Remaining Ace count
- Game status
- The GraphQL API should also provide a way to,
- Start a new game
- Deal a new hand
- Reset the in-progress game
- Display "Game Over" on completion. If the User wins, also display "Winner"; otherwise, display "You Lose. Better luck next time!"
- Unit tests.
Bonus!
- Streak of wins/loses/games played in (can be the last hour, but should be configurable)
- Storing user details, login/out
- Rig the game (e.g. player always wins)
- Custom deck support (e.g. other deck images, other lengths of decks, not just 52 cards)
- Authentication
Feel free to use any additional libraries, except for out-of-the-box deck/card dealing.
You can run a sample query at localhost:8000/graphql/
query {
me {
username
email
}
}
There are two primary ways we suggest:
- Docker (not tested on Windows, you're on your own)
- Local development
make python-start
This will pull the containers, install everything needed and start the server on localhost:8000.
You can check other Docker related commands in the provided Makefile
and docker-compose.backend.yml
. See docker/Docker.server/Dockerfile
for the Docker setup, and note that poetry is set up to export to requirements.txt
.
On MacOS, use brew to manage installation of supporting programs, as it keeps things tidy.
On Windows, use WSL with Ubuntu 20.04 or later. You can also install pyenv (check out pyenv-win) and postgres natively. Docker is not officially supported.
For backend, the recommended way is to use poetry and pyenv. All of the commands in this section are from the server
folder.
Install poetry. To manage python versions, we recommend installing pyenv
. See the poetry
documentation for details.
Then install Python dependencies:
cd server/
# try one of these
pyenv install 3.9.9 # or pyenv local 3.9.9
poetry env use ~/.pyenv/versions/3.9.9/bin/python
poetry install
# or
poetry install --python `which python3`
If you don't have it already, you'll also want to install Postgres. Version 10 or later should be fine.
If you have issues:
- Check which pyenv version homebrew installs https://github.com/Homebrew/homebrew-core/blob/master/Formula/pyenv.rb#L4
- See what versions of python that pyenv version supports: https://github.com/pyenv/pyenv/tree/master/plugins/python-build/share/python-build
- On MacOS using M1 chip,
poetry install
may fail with an error forpyscopg2-binary
(ld: library not found for -lssl
). Check out this article to install psycopg2.
Copy example env vars to .env
. You might need to change DATABASE_URL
based on your environment.
cp ../.env.example ../.env
Create the uplifty
database:
createdb uplifty
Load the sample user data:
poetry run ./manage.py migrate
poetry run ./manage.py loaddata uplifty/fixtures/users.json
poetry run ./manage.py runserver
Now you can go to http://localhost:8000, http://localhost:8000/graphql/, or http://localhost:8000/admin/ for the Django admin.
Log in to the admin with the sample test user from below and try the sample query from the challenge.
CI runs black, isort, flake8. Configuring your editor/IDE appropriately will make it easier for you to ensure passing CI tests when you submit.
poetry add <package name> # this automatically adds it to pyproject.toml and poetry.lock
If you manually update pyproject.toml
, make sure you run poetry update
to update the lockfile.
If you run with docker, and your package is suddenly missing, you may need to rebuild the images using:
make python-build
Please run the tests, and lint your backend code. This helps us review code, as it's already consistent with this project.
make python-lint
make python-test
Or check out the Makefile
for other options.
- PostgreSQL 10+
- Python 3.9+
- Django 3
- django-environ for easy environment configuration via
.env
files
The database is created with a sample test user:
Name | Value |
---|---|
Username | interview |
interview@uplift.agency | |
Password | uplifty |
You can change these in the Django admin if you wish.
If you are working with node instead of Django, we'd like you to do the same backend challenge with TypeScript and GraphQL.
There is a starter server you can use in node-server/
, and it runs CI using .github/workflows/backend_node.yml
. Please make sure the build passes.
If you are working with PHP instead of Django, we'd like you to do the same backend challenge with Laravel and GraphQL.
There is a starter server you can use in php-server/
; please see the README in that directory.
It runs CI using .github/workflows/backend_php.yml
. Please make sure the build passes.
We're happy to see you want to do both. Please check the frontend and backend sections for instructions on the logic. If you prefer to work locally, also check the instructions on how to get each component running.
make fullstack-python-start
Also, you'll need to set up the Apollo client for the API:
-
Here you can find resources on how to setup Apollo. If you install packages locally, make sure to also
make fullstack-python-build
after you finish the setup to have everything working in Docker. Otherwise, if you have the containers running, you canmake frontend-bash
andnpm install
/yarn add
any package there. -
Here you can find resources on GraphQL code generation.
-
Run
make python-schema
to updateschema.json
on the backend. -
Uncomment the server volume in
docker-compose.frontend.yml
. You need this so that../server/schema.json
is visible in the frontend container. -
Create
frontend/codegen.yml
and add the following:overwrite: true schema: '../server/schema.json' documents: null generates: ./src/generated/graphql-types.ts: plugins: - 'typescript' - 'typescript-operations' - 'typescript-react-apollo'
-
Add
"gql-codegen": "graphql-codegen --config codegen.yml"
infrontend/package.json
and run it.make frontend-bash yarn gql-codegen
If you see the following the configuration was successful:
✔ Parse configuration ✔ Generate outputs Done in 2.45s.
This code is intended to be private. You are not allowed to share any of the base template code without Uplift's express permission. Please reach out to us before you share any of the code in this repository with others.
That said, we understand you may want to show others your work. If you're proud of your work on this exercise and want to share it with future companies or add to your portfolio, we kindly request you help us keep the codebase as private as possible. If it's easy for other candidates to find a good coding exercise submission, they will, and then we have to invest a bunch of time to change the requirements so that old examples cannot be used. Unfortunately we've had cases of applicants copying examples they found.
Here are some ideas to share this more privately. We would really appreciate if you followed them:
-
Host the code privately and only give access to others upon request. This is the best way to ensure it's not easy to find.
-
Share only a few of the files, but not enough to tie everything together.
-
Host it on your own server, or bitbucket instead of github.