merging in material that will be folded in

This commit is contained in:
2021-08-03 21:48:37 -05:00
parent ca1e9cebd4
commit e6f1eae94f
71 changed files with 5990 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
---
title: 4. Developer Workflow
sidebar: Handbook
showTitle: true
hideAnchor: true
---
If you haven't already, it's worth your time to read [Contributing to PostHog](https://posthog.com/docs/contributing).
Most developers use either [vscode](https://code.visualstudio.com/) or [pycharm](https://www.jetbrains.com/pycharm/) but
you are free to use whatever IDE makes the most sense to you.
## Backend w/ Vscode
1. Create a git branch
2. Start PostHog with `bin/start`
3. Open app in Chrome and login
4. Open Chrome devtools to network tab
5. Navigate to scene (aka screen or page) and click on the area of interest
6. Find network request in devtools and find request
- Request maps to ./posthog/api/*.py, i.e. http://localhost:8000/api/insight/funnel/?insight=FUNNELS -> ./posthog/api/insight.py:197
7. Make code changes including tests
- Use [print()](https://realpython.com/python-print/) as needed for debugging
- Some developers prefer [Pycharm](https://www.jetbrains.com/pycharm/) for local development
8. Run backend tests
- `bin/tests posthog` runs only posthog tests excluding ee tests
- `./bin/tests ee/clickhouse/queries/test/test_trends.py -k test_active_user_math` for specific tests
9. Commit changes to git branch
10. Open PR for review
- Include Github issue number `#1234` which Github will automatically link for you
## Frontend w/ Vscode
1. Same as backend 1-5
2. Find frontend code, i.e. `frontend/src/scenes/insights/Insight.tsx`
3. Use `console.log` liberally
3. As of writing, there are no unit tests for the frontend although we do have integration tests for the frontend via Cypress
4. Same as backend 9-10
## Alternative: Pycharm
Some developers prefer to use [Pycharm](https://www.jetbrains.com/pycharm/) and for
good reason. While there are many benefits, below you'll find a few keys benefits.
1. `Debugging and no print() statements` this is probably the biggest win in my opinion.
Since we are learning a new codebase there is no shame in having an assistant. Pycharm
will show you the call stack and variable values. This is huge for understanding what
is going on.
2. `Code navigation` when you are new to a codebase, moving easily through the code
can be a real challenge, especially when there are multiple layers of abstraction.
Pycharm allows you to Ctrl+Click nearly all methods to jump to their definitions.
While editors like vscode have a similar feature, you'll find that Pycharm works
in cases where vscode does not.
3. `Run configurations` make starting celery, django, and webpack services simple. It's
mostly just clicking things.
4. `Excellent TypeScript support` with code completion and type checking directly in your
editor.
5. `Click instead of type` which means that you spend much more time typing code than
running commands. Nearly everything in Pycharm is clickable.
Pycharm offers a try it for free 30-day trial. It's recommended that you use it for at least
that amount of time before you buy. I recommend watching [The Future of Programming](https://www.youtube.com/watch?v=8pTEmbeENF4)
that will blow your mind and perhaps give you a new perspective on tools like these.
**[Next: Technologies to learn](technologies-to-learn)**

View File

@@ -0,0 +1,27 @@
---
title: 3. Getting Started
sidebar: Handbook
showTitle: true
hideAnchor: true
---
## First goals
1. Set up your dev environment and configure with your IDE
2. Get PostHog running locally on Postgres: [http://localhost:8000](http://localhost:8000). You'll need postgres, redis, celery, and django running.
3. Successfully run PostHog tests: `bin/tests posthog` (which omits Clickhouse tests)
4. Create [your first PR](https://github.com/PostHog/posthog/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)
and have it be approved. If you work for PostHog someone (Tim or small team lead) will suggest the
first assignment.
## Suggested learning roadmap
1. [Setup your local dev environment](https://posthog.com/docs/developing-locally)
2. Ask your [PostHog Buddy](https://posthog.com/handbook/people/onboarding#posthog-buddy) for a product walk-thru. It's important to get to know the product you are building. I recommend doing this before you become deeply involved in it's internal design. This is a great time to view our product through the eyes of our users.
3. [Review PostHog Project Structure](https://posthog.com/docs/project-structure)
4. Learn [React](https://reactjs.org/docs/hello-world.html), [Redux](https://redux.js.org/introduction/core-concepts), and [Kea](https://kea.js.org/docs/introduction/what-is-kea) - If you're experienced with frontend frameworks I suggest going directly to Kea.
5. Take a brief overview of [Python](https://learnxinyminutes.com/docs/python/).
6. Complete [Django Tutorial 1-5 of 7 parts, skip 6+](https://docs.djangoproject.com/en/3.1/intro/tutorial01/). If you're interested in learning more about Django, pick a copy of [Django book](https://www.feldroy.com/products/two-scoops-of-django-3-x). The company will happily pay for this since they [believe in training us to do our jobs with excellent](https://posthog.com/handbook/people/training). Great place to work, right?
**[Next: Developer Workflow](developer-workflow)**

View File

@@ -0,0 +1,22 @@
---
title: 2. Getting To Know PostHog
sidebar: Handbook
showTitle: true
hideAnchor: true
---
It's surprising how enjoyable and calming learning about PostHog's people can be.
You'll find [all their bios here](../../people/team). It's well worth your time!
### PostHog via James Hawkins, CEO
Additionally, James put together some great YouTube videos. I watched them all.
- [Why we built our business in the first place](https://www.youtube.com/watch?v=TIxxIEEvczM)
- [Open Source is Eating SaaS](https://www.youtube.com/watch?v=bh3j_9jVeqg)
- [How we raised a $3M seed round a few weeks after starting our open source project](https://www.youtube.com/watch?v=lJ41-95Ey3w)
- [Open source business models - your choices and how PostHog makes money](https://www.youtube.com/watch?v=L1Ovbzs7vyo)
- [We've never met each other in real life. How we designed PostHog for remote work from day one.](https://www.youtube.com/watch?v=rRwzJiljpSA)
- [Coffee + iPads + Feedback = A day in the of PostHog's graphic designer](https://www.youtube.com/watch?v=xlODCLrZyvM) by Lottie (helpful to see the design side of PostHog)
**[Next: Getting started](getting-started)**

View File

@@ -0,0 +1,75 @@
---
title: 1. Beginner's Guide
sidebar: Handbook
showTitle: true
hideAnchor: true
---
## Introduction
The *Beginners Guide* started as a project to help me and others get up to speed on PostHog's tech stack.
I also wanted to include bits of advice to make the process encouraging to make working on PostHog even better.
I needed this approach personally since I've been hardcore programming in other languages and tech stacks
for years so most of PostHog's tech stack was newish to me.
## Consider your learning style
Some people like to jump in and go. Some people like to read the docs. I'm the latter. Another way of saying it
that I'm a holistic learner. My plan was to spend part of the time accomplishing work given to me and part
of the time on intentional education. The point is to know your own learning style so that you can be effective.
To that end, if you're a get started now type, you'll appreciate the
[getting started section](getting-started).
It's also important to note that whatever you learn needs to be reviewed several times. It doesn't
matter what learning style you have because review is essential to learning from a neuroscience
perspective. If you create small exercises for yourself such as the projects I've created in this repo
you'll do even better. The good news is that this process doesn't take up an extraordinary amount of time.
## A word about mindset
> You get more than you give.
My mindset is one of wanting to get the most out of life. For me, in part, that
means being excellent and taking full ownership of my career. Learning new
material can be overwhelming not to mention difficult. But remember this:
*it's worth it*! Investing in yourself makes for a better, more capable
version of you. Therefore, trust the difficult process of learning and elevate
your skills. The future you will thank you for your hard work.
If you get discouraged come back to this section.
## What has helped me personally
First thing to remember: starting a new job is like beginning a book in the middle of a
series where the characters are well-formed, and the story is far along. It's fair to say,
you have no idea what is going on. You can read words and understand but not understand
why they are being said. There our goal is to *develop a solid mental model for the codebase*.
> “You dont care about the answer until you have the question.” - Unknown
- On my first day, I was given an assignment to work on. It began the process of showing me what I needed to learn. Struggling to complete the assignment helped me to *have the question* from the quote above.
- Reading the [project structure doc](/docs/project-structure)
- Browsing the [issues in GitHub](https://github.com/PostHog/posthog/issues) by playing with the various labels. This helped me get a better feel for PostHog's communication style and open-mindedness.
- Pairing with Tim & Eric. They used devtools to examine network traffic, console.log, and I was able to ask specific questions. It was basic stuff and reminded me to use the basic tools I've been using for years. I guess the anxiety of a new job confused my brain a little.
- Reading the kea docs. This is *clutch* to understand the frontend. It's a rather nice library but you won't make progress without understanding Kea.
- Creating a simple app with create-react-app with typescript support `yarn create react-app learn-kea-typescript --template typescript`
> "Take care of yourself. There's no need to burnout in the first month." - Eltje
- Eltje encouraged me to take care of myself, so I did.
> "So, what?!" - [Dare: The New Way to End Anxiety and Stop Panic Attacks](https://www.amazon.com/Dare-Anxiety-Stop-Panic-Attacks/dp/0956596258/) where "D" stands for defuse the anxiety by considering the worst and saying so what.
- Often I felt anxious about my daily contributions. Using the quote above really helps deal with this kind of anxiety. So what if I fail to deliver these assignments timely?! I'm an expert and in time I'll be a great asset to PostHog.
- Additionally, it's important to remember to trust the process. Being new (bad) at something isn't a great feeling initially until you realize that it's a part of the process. Soon you'll be good. It's better to reframe and remember that you only get to have new eyes once. Plus, it's fun to learn new things.
> "When you are working, close your email and slack. No one is watching to see if you are online. In fact, it's the opposite." - Tim, CTO
- Tim told me this on the first or second day, and it was liberating. It allowed me to think of my role as a true `async` open-source contributor. Do what needs to be done so that you can be the most effective.
> Read the docs
- For my learning style, this has been a **must**. I'm keeping a list of resources for learning I've used.
- I also spent time creating projects as you see in this repo which helped me consolidate the knowledge I was gaining.
**[Next: Getting to know PostHog](getting-to-know-posthog)**

View File

@@ -0,0 +1,32 @@
---
title: Our Notes On Django
sidebar: Handbook
showTitle: true
hideAnchor: true
---
## Start here
If, like me, you haven't worked with Django before, the best place to start with is
[Writing your first Django app](https://docs.djangoproject.com/en/3.1/intro/tutorial01/)
from the official Django website. This gives you a quick understanding of the major
parts of Django without needing to read an entire book to get it.
## Useful Django commands
- `django-admin startproject mysite` - creates Django project
- `python manage.py runserver` - starts Django web server (optionally add a port at the end `8080`)
- `python manage.py startapp polls` - creates Django app in project
- `python manage.py makemigrations polls` - creates migration scripts in migrations folder
- `python manage.py sqlmigrate polls 0001` - shows SQL that will run for this migration but doesn't perform it
- `python manage.py migrate` - performs all migrations
- `python manage.py shell` - puts you in a Django ORM shell to play with the models on the command-line
- `python manage.py createsuperuser` - creates super user for django admin app which comes by default with all Django projects, url `/admin`
- `python manage.py test polls` - run tests for polls app
## Useful resources
- [Writing your first Django app](https://docs.djangoproject.com/en/3.1/intro/tutorial01/). I recommend
reading Parts 1-5 of the 7 parts, skip 6+ since they are not relevant to PostHog. We do use Django built-in testing so part 5 is required reading.
- [Two Scoops of Django (e-book)](https://www.feldroy.com/products/two-scoops-of-django-3-x)
**[Back: Technologies to learn](../technologies-to-learn)**

View File

@@ -0,0 +1,103 @@
---
title: Our Notes On Docker
sidebar: Handbook
showTitle: true
hideAnchor: true
---
## Docker Nomenclature and Notes
- `Docker Image` - the actual package, **artifact** which can be shared with others, docker images are built in layers via Dockerfile
- `Docker Container` - a *running* instance of a docker image, file system is virtual, contains a port for communication
- Docker run - command which executes *pull* and *start* (only pulls images we do not have locally)
- Docker vs Virtual Machine
- Operating System = Hardware > OS Kernel (layer 1) > Applications (layer 2)
- Docker = Virtualization of applications (layer 2)
- Virtual Image = Virtualization of OS (layer 1)
- Benefits of Docker = images are much smaller, runs faster
- Benefits of VM = you can run different OS (Windows on Linux) since it has it's own OS Kernel
- Docker Port vs Host Port
- Multiple containers may use the same port
- Bind host port to docker port, i.e. host 3000 -> docker 3000, host 3001 -> docker 3000
- `Docker Compose`
- Configuration file specifying *docker commands* to make it easier to work with
- Automatically handles creating a common *docker network*
- Docker compose is usually installed with docker so you already have it
- `Docker Volumes`
- Provides data persistence between host machine and docker containers
- The data between volumes is replicated between the host and docker container volumes
- 3 docker volume types: specified, anonymous, and named volumes, named volumes on the host are managed by docker
- Production should use *named volumes*
- Container Mongodb = /data/db
- Container MySQL = /var/lib/myself
- Container Postgres = /var/lib/postgres/data
- Host Windows = C:\ProgramData\docker\volumes
- Host Linux = /var/lib/docker/volumes/[hash]/_data
- Host Mac = /var/lib/docker/volumes/[hash]/_data
- `screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty` add access linux VM on mac where data is stored, `ctrl + a + k` to exit screen session
## Basic commands
- `docker pull` downloads a docker image locally
- `docker images` shows a list of local docker images and their sizes
- `docker run` run a docker container, it's two commands in one *docker pull* and *docker start*
- `docker run -d` runs the docker container in *detach mode*
- `docker run -p` binds the container to host port i.e. *-p6000:6370*, *-p [host]:[container]*
- `docker run --name` give the container a name so that you do not need to use the SHA
- `docker run -d -it python` runs python images in *interactive terminal* mode
- `docker run -e` runs an image with an environment variable
- `docker run -net` specify a docker network to run within
- `docker start` start a container, retains the settings from the run command
- `docker stop` - stops a container
- `docker ps` shows *running* containers
- `docker ps -a` shows *running and not-running* containers
- `docker logs` shows the *standard output* of the *running* container
- `docker logs -f` follow the *standard output*, similar to *tail -f*
- `docker exec -it` runs the container with interactive terminal
- `docker network ls` shows a list of the internal docker network
- `docker network create` create a docker network
- `docker build -t my-app:1.0 .` builds an image from a *Dockerfile* in the current directory
- `docker rm` removes a docker container which you need to do before docker rmi
- `docker rmi` removes a docker image, i.e. docker rmi my-app:1.0
- `docker run -v` mounts host filesystem to docker container filesystem
## Docker Compose
- `docker-compose -f mongo.yaml up` pulls, starts, and creates container network
- `docker-compose -f mongo.yaml up -d` runs containers in *detached mode*
- `docker-compose -f mongo.yaml down` stops container, removes container, and stops container network
## First Dockerfile
```docker
FROM python:3.9-alpine3.13
RUN apk add bash nodejs
COPY hello.* /
CMD ["bash"]
```
## First commands
- `docker build .` builds the container
- `docker run --name [name] [sha]` installs the container
- `docker run -it --name [name] [sha]` installs the container and starts in interactive mode
- `docker ps` shows all the running containers
- `docker ps -a` shows all the running and exited containers
- `docker stop [name]` stop container
- `docker start -ai [name]` start container interactively
- `docker rm [name]` removes container
## Resources
- [Creating your first Dockerfile, image and container](https://www.youtube.com/watch?v=hnxI-K10auY) great place to start
- [Docker Tutorial for Beginners [FULL COURSE in 3 Hours]](https://www.youtube.com/watch?v=3c-iBn73dDE) most helpful
- [Docker For Beginners: From Docker Desktop to Deployment](https://www.youtube.com/watch?v=i7ABlHngi1Q)
## Related Resources
- [Kubernetes Tutorial for Beginners FULL COURSE in 4 Hours](https://www.youtube.com/watch?v=X48VuDVv0do) To manage distribution of contains across many servers
**[Back: Technologies to learn](../technologies-to-learn)**

View File

@@ -0,0 +1,89 @@
---
title: Our Notes On Kea
sidebar: Handbook
showTitle: true
hideAnchor: true
---
## Actions
- All code lives inside `logic` which is created with `kea({ ... })`
- Files are typically named `[name]Logic.js|ts`
- `import { useActions } from 'kea'` provides access to action all functions
- All operations start from `actions`
- The mental model for actions is that of *event capturing*, they signal intent
- Sample action: `increment: (amount) => ({ amount })`
- **Actions** map to `reducers` and `listeners` to perform operations
- Actions can invoke several reducers if the name of the action maps to multiple reducers
- Actions defined with `someActions: true` are actions with no arguments
## Reducers
- Reducers define `state` and `operations` on that state.
- `import { useValues } from 'kea'` provides access to the state
- Sample reducers: `counter: [0, { increment: (state, { amount }) => state + amount}]`
- Notice how increment is the same name as the action
- Reducers should never mutate the state directly, they must be pure functions
## Listeners
- Listeners are how you do `side-effects` and async calls to load data
- Listeners may invoke other actions via `actions`, example: `listeners: ({ actions, values }) => ({ ... })`
- Listeners are `async` functions
- Notice we have access to actions and values in the listeners functions
- *Set this or that* is better done by reacting to actions
## Loaders
- Available via the `kea-loaders-plugin`
- Encapsulates the pattern of action > listener > loading > success | failure
- Example: `users: [[], { loadUsers: async () => await api.get('users') }]`
## Selectors
- Selectors handle mapping data across reducers
- Similar to computed values in Vue
## Values
- `import { useValues } from 'kea'`
- You can access values frorm React with useValues or from listeners via listeners function
## Input objects vs functions
- Any of kea's built-in primitives: actions, reducers, listeners, etc. may be declared with an object or function
- Functions are invoked lazily
- Functions are passed 1 argument which can be destructured for actions and values
- Use objects first then functions as you need them
## Props
- Using kea logic as a function allows you to pass in props which are available as destructured props for primitive key functions
## Keyed logic
- If you give your logic a key, you can have multiple independent copies of it. The key is derived from props
- Example: `key: (props) => props.id`
## Breakpoints
- Serves as a debounce function or out of order network calls
## Events
- Handles lifecycle events
## Defaults
- Allows you to specify default values instead of doing them in the reducers
- Defaults may be a function as well to calculate the default values
## Connecting kea logic together
- You may [connect logics together](https://kea.js.org/docs/guide/additional#connecting-logic-together)
## Useful resources
- [Kea](https://kea.js.org/docs/introduction/what-is-kea)
**[Back: Technologies to learn](../technologies-to-learn)**

View File

@@ -0,0 +1,53 @@
---
title: Our Notes On Python
sidebar: Handbook
showTitle: true
hideAnchor: true
---
Along with reading about any given programming language it's necessary to use that
knowledge. I've prepared exercises that will help you use the knowledge you are
learning.
Start by reading [Python via Learninyminutes](https://learnxinyminutes.com/docs/python/)
then work to complete the exercises below.
## 1. Fibonacci
You can learn about the [fibonacci here](https://en.wikipedia.org/wiki/Fibonacci_number). Fibonacci
sequence means each number is the sum of the two preceding ones, starting from 0 and 1.
The sequence looks like this `0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144...`
**Exercise: Calculate the fibonacci sequence up to 100**
## 2. Invictus text processing
1. Read [invictus.txt](https://raw.githubusercontent.com/buwilliams/learn-posthog/main/docs/exercises/02_invictus.txt) into a string
2. Split the string an array of words and print them out
3. Correct words with invalid characters and print the cleaned words out
4. Create an array of maps of all unique words and how many times they occurred
5. Sort the array of maps by the number of times they occurred in descending order
6. Convert the code into a class, implement interfaces and type checking if applicable
## More exercises
- [Programming Problems](https://adriann.github.io/programming_problems.html)
## Create your own exercises
One interesting strategy is to:
1. Buy/find a programming book you're interested in.
2. As your read, create an exercise for that chapter.
3. Code the exercise that you created before moving on.
4. Rinse and repeat until you've finished the book.
By creating the exercise and solving it, you'll learn better than if you just read the chapter.
Remember that many programmers are lazy and are unwilling to put this kind of effort. You'll
be light years ahead of your peers as you apply yourself.
## Useful resources
- [Python via Learninyminutes](https://learnxinyminutes.com/docs/python/)
**[Back: Technologies to learn](../technologies-to-learn)**

View File

@@ -0,0 +1,116 @@
---
title: Our Notes On React
sidebar: Handbook
showTitle: true
hideAnchor: true
---
The [React docs](https://reactjs.org/docs/getting-started.html) are great for getting from zero to one.
## Hooks
I found hooks somewhat counterintuitive at first, but they're very powerful once you grasp them. Refer to the [Rules of Hooks](https://reactjs.org/docs/hooks-rules.html). - @samwinslow
1. Only call from the top level of a functional component
2. Do not call outside a functional component or from plain JS (you can call from custom hooks)
### useState
Uses destructured array assignment syntax
`const [value, setValue] = useState(initialValue)`
An updater function can be passed to the setter so that multiple updates can be called in sequence, or to merge-update the state via spreading if it's an object. The updater is a pure function which takes previous state and returns next.
```jsx
// bad
setValue(value + 1)
setValue(value + 1)
// good
setValue(value => value + 1)
setValue(value => value + 1)
```
In general, derive data while rendering rather than storing derived values in state (e.g. filtering local data). However, if expensive filtering or join operations are to be performed and/or the component re-renders frequently, a memoized state management library might be better.
### useEffect
Takes a callback function which may have (potentially global) side effects. Runs on every re-render by default.
```jsx
function EffectExample() {
const [value, setValue] = useState(initialValue)
useEffect(() => {
document.title = `The value is now ${value}`
})
return (
<div>
<p>{value}</p>
<button onClick={() => setValue(value => value + 1)}>Use Effect</button>
</div>
)
}
```
The rendered value is not a special data binding that causes it to listen. It is merely a reflection of a new value rendered as a result of calling the setter.
Can return a cleanup function from the effect and declare when it should run
```jsx
function ApiStatus({ service }) {
const [isOnline, setOnline] = useState(null)
const { id } = service
useEffect(() => {
const handleStatusChange(status) => {
setOnline(status.isOnline)
}
SomeApi.subscribe(id, handleStatusChange)
return () => SomeApi.unsubscribe(id, handleStatusChange)
}, [id]) // Only run when `id` changes (sync to state)
// rendering
}
```
### useLayoutEffect
Same as `useEffect`, but runs callback synchronously during commit lifecycle phase
### useMemo
Recalculates value only when dependencies change
### useCallback
Updates callback function reference when dependencies change
### useRef
Mutable ref used to access returned child.
- Persists between renders
- Default: `{ current: null }`
- Plain object; mutating does not trigger re-renders
### Custom Hooks
Listeners and API connections can be extracted to a custom hook and reused
Examples from popular libraries:
- React-Redux: `useSelector`, `useDispatch`
- React-Router: `useHistory`, `useLocation`, `useParams`
- `useFormState`
## Useful resources
- [Dan Abramov - A Complete Guide to useEffect](https://overreacted.io/a-complete-guide-to-useeffect/)
- [Mark Erikson - A Complete Guide to React Rendering Behavior](https://blog.isquaredsoftware.com/2020/05/blogged-answers-a-mostly-complete-guide-to-react-rendering-behavior/)
**[Back: Technologies to learn](../technologies-to-learn)**

View File

@@ -0,0 +1,23 @@
---
title: Our Notes On TypeScript
sidebar: Handbook
showTitle: true
hideAnchor: true
---
The best way to learn TypeScript is to read introductory material then get hands on with exercises.
## Exercises
You can complete the exercises on the [TypeScript Playground](https://www.typescriptlang.org/play)
You can use the same [exercises for Python](python) as starting place.
## Great places to learn
- [TypeScript via learnxinyminutes](https://learnxinyminutes.com/docs/typescript/)
- [TypeScript in 5 minutes](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html)
- [TypeScript Handbook](https://www.typescriptlang.org/docs/handbook/intro.html)
**[Back: Technologies to learn](../technologies-to-learn)**

View File

@@ -0,0 +1,33 @@
---
title: 5. Technologies To Learn
sidebar: Handbook
showTitle: true
hideAnchor: true
---
Each of the links below will send you to the best resources for learning I found. As I went through learning the
various technologies, I took notes. Below you'll find all the notes that I took along with resources I felt were
particularly useful. I'd suggest using *our notes* links as you would a cheatsheet.
## Backend
- [Python](https://www.python.org/) ([our notes on Python](notes/python))
- [Django](https://www.djangoproject.com/) ([our notes on Django](notes/django))
- [Django Testing](https://docs.djangoproject.com/en/3.1/intro/tutorial05/)
- [Pytest](https://docs.pytest.org/en/stable/getting-started.html)
- [Clickhouse](https://clickhouse.tech/) (enterprise database)
- [Celery](https://docs.celeryproject.org/en/stable/) (we use Redis as Celery's message broker)
- [Docker](https://www.docker.com/) ([our notes on Docker](notes/docker))
## Frontend
- [React](https://reactjs.org/docs/hello-world.html) ([our notes on React](notes/react))
- [Redux](https://redux.js.org/introduction/core-concepts)
- [Kea](https://kea.js.org/docs/introduction/what-is-kea) ([our notes on Kea](notes/kea))
- [TypeScript](https://www.typescriptlang.org/) ([our notes on TypeScript](notes/typescript))
## Useful tech
- [Tmux](https://github.com/tmux/tmux/wiki)
- [Fish](https://github.com/fish-shell/fish-shell)
- [Zsh](https://github.com/ohmyzsh/ohmyzsh)