Skip to content

Commit 2fb607b

Browse files
committed
docs: move docs to local markdown files
1 parent 2d179d7 commit 2fb607b

File tree

4 files changed

+171
-3
lines changed

4 files changed

+171
-3
lines changed

README.md

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
![petmemo](https://github.com/sarneeh/petmemo/assets/11553624/fa53aa5a-dc09-401b-a3b0-68237bf03333)
1+
![petmemo](docs/assets/logo.jpg)
22

33
A showcase application built with Vite and React. Powered by [The Cats API](https://thecatapi.com/).
44

55
[Live demo](https://petmemo-sarneeh.vercel.app/)
66

77
## Prerequisities
88

9-
Important! Unfortunately the Cats API does not work properly without an API key. If you want to run the app locally, you need to grab a key from the [Cats API](https://thecatapi.com) website and put it in a `.env` file, like this:
9+
Important! The Cats API does only support filtering with query parameters when used with an API key. If you want to run the app locally, you need to grab a key from the [Cats API](https://thecatapi.com) website and put it in a `.env` file, like this:
1010

1111
```
1212
VITE_API_KEY=YOUR_KEY_HERE
@@ -60,4 +60,45 @@ Icons have been taken from an open-source project called [Lucide](https://lucide
6060

6161
## Architecture
6262

63-
For a detailed description and overview of the architecture, check [this document](https://www.craft.me/s/Qb7mtyIAi6s62S).
63+
For a detailed description and overview of the architecture, check [this document](docs/architecture.md).
64+
65+
## Shortcomings / Todo List
66+
67+
A list of issues and things that I'm aware of that should be improved to make the project production-ready.
68+
69+
### Unit tests
70+
71+
There are no unit tests. No tests for the domain logic, no tests for the UI components. This should be surely addressed.
72+
73+
### End-to-end tests
74+
75+
Like above, it would be great to have some end-to-end tests of the app. If so, I'd probably suggest Cypress.
76+
77+
### Semantic HTML
78+
79+
To be honest, I didn't care about it too much knowing the time limitations so I spammed `div`'s wherever I could 😅 There are certainly some places for improvement here.
80+
81+
### UI / UX
82+
83+
There are a few problems and places which could be improved:
84+
85+
- accessibility
86+
- keyboard navigation
87+
88+
### Continuous integration / Continuous deployment
89+
90+
Would be great to have basic build/test/lint/typecheck GitHub Actions that could check stuff every commit without the need to do it locally.
91+
92+
### Bugs
93+
94+
- I run into an issue with the grid on Safari - it renders initially stretched out and fixes itself on interaction (without any rerender). This seems like a Safari bug in a grid + aspect-ratio scenario. I tried to fix this issue but after a few hours I gave up and left it as is as I had to finish other elements of the solution ☹️
95+
96+
### Other improvements / ideas
97+
98+
- limited time for each turn (counter)
99+
- setting to choose between cats/dogs
100+
- multiplayer online (lobby system)
101+
- player profiles
102+
- player leaderboards
103+
- tournamets
104+

docs/architecture.md

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# petmemo
2+
3+
This is a document describing the architecture, known limitations and shortcomings of the [petmemo](https://github.com/sarneeh/petmemo) game. You will learn about how the application has been structured and what was the idea and rationale behind it.
4+
5+
# Architecture
6+
7+
## Inspiration
8+
9+
The architecture is inspired by a few resources found in the web:
10+
11+
- [Feature-Sliced Design](https://feature-sliced.design/)
12+
- [Khalil Stemmler - Client-Side Architecture](https://khalilstemmler.com/articles/client-side-architecture/introduction/)
13+
- [Juan Otálora - Folder structure in a React hexagonal architecture](https://dev.to/juanoa/folder-structure-in-a-react-hexagonal-architecture-h77)
14+
15+
It does not strictly follow any of those suggestions, but it's inspired by some ideas from each of them to compose a solution that suits the needs of the project.
16+
17+
## Structure
18+
19+
The app is devided in 4 base layers: **app, modules, pages** and **shared**. Some of the layers have sub-layers (modules, shared) and some are flat (app, pages).
20+
21+
![structure.png](assets/structure.png)
22+
23+
You can find detailed information about each of the layers (and its sub-layers) below.
24+
25+
### App
26+
27+
Simple, flat layer where we put all app-wide settings, styles, providers, routing etc. Elements of this layers should not be related to any domain logic of the application and suit mostly for app bootstrap.
28+
29+
### Modules
30+
31+
The core of the whole application. It consists of domain slices that are separated in sub-layers, similar to the [shared](#shared) layer. Elements from this layer are used to build up whole pages in the [pages](#pages) layer.
32+
33+
#### Model
34+
35+
This sub-layer consists of multiple elements related to the domain slice:
36+
37+
- `state` - state management store, consists of module **state** (data) and **actions** (app events)
38+
- `selectors` - reusable state selectors
39+
- `hooks` - React hooks that encapsulate some of the app state selection and actions (domain logic) for increased testability
40+
- `subscriptions` - state subscription creators to simplify implementation of state change side-effects and increase reusability
41+
- `types` - TypeScript types and interfaces related to the domain slice
42+
43+
Those are building blocks that encapsulate some of the domain logic to decrease inlined domain logic in the module [ui](#ui) components.
44+
45+
#### Infrastructure
46+
47+
Infrastructure elements related to the domain. Often composed from reusable elements from `shared/infrastructure`.
48+
49+
Examples: `CardRepository`, `CardAPIClient`
50+
51+
#### Services
52+
53+
Classes that help decouple some of the domain logic. Ideally split to as small chunks as possible to allow easier testability and reusability.
54+
55+
#### UI
56+
57+
Domain-related components, often "smart" with logic in it.
58+
59+
Examples: `GameBoardCard`, `GameStartButton`
60+
61+
#### Utils
62+
63+
Helper functions related to the domain that do not fit directly to any service or that may be used by multiple services.
64+
65+
Examples: `isCardRevealed`
66+
67+
### Pages
68+
69+
Compositional layer that consists of components that construct full pages from various app modules. Should not contain any domain logic.
70+
71+
### Shared
72+
73+
Shared layer that consists of elements that are not related to any domain.
74+
75+
#### Infrastructure
76+
77+
Reusable infrastructure elements like API clients, state managament addons.
78+
79+
Examples: pre-configured API client with error handling, interceptors, state management offline storage hooks
80+
81+
#### UI
82+
83+
Reusable pure components not related to any domain logic.
84+
85+
Examples: `Button`, `Card`
86+
87+
#### Utils
88+
89+
Reusable helper functions not related to any domain logic.
90+
91+
Examples: `replaceItemAtIndex`, `preloadImages`
92+
93+
## Rules
94+
95+
There are a few rules that need to be followed so that the architecture would make sense and so it wouldn't provide more problems than benefits:
96+
97+
- All of the `modules` should have clear entrypoints and only those entrypoints should be used. This ensures encapsulation and usage only of the publicly exposed interfaces. Example:
98+
- bad: `import { GameCard } from '@/modules/game/ui/GameCard'`
99+
- good: `import { GameCard } from '@/modules/game'`
100+
- There should be clear importing rules throughout the different layers to prevent unwanted situations like:
101+
- `app` importing from the `modules` layer
102+
- `pages` importing from `app` layer
103+
- `modules` importing from `pages` layer
104+
105+
### Automation
106+
107+
Humans are bad in remembering things and ensuring everything is in the right order. When there are tight deadlines - everything will eventually fall apart 🙂 To prevent this, we should automate the process as much as possible to ensure architecture consistency.
108+
109+
For this, petmemo is using a great eslint plugin called [eslint-plugin-boundaries](https://github.com/javierbrea/eslint-plugin-boundaries), which [properly configured](https://github.com/sarneeh/petmemo/blob/main/.eslintrc.cjs#L81-L116) can automate checking the rules described above.
110+
111+
## Rationale
112+
113+
This architecture is something I've been working on on various project and it's still an in-progress. It's definitely scaling a lot better than the most common flat components/containers approach and results in a lot better code structure thanks to the separation of domain elements.
114+
115+
The biggest benefits that I've found comparing to other architectures is:
116+
117+
- clear distinction between UI and general logic that's tied to some kind of a domain or if it's for general purpose
118+
- better testability and maintainability of the domain logic
119+
- thanks to splitting the domain into reusable hooks/services/selectors you can test small chunks of logic with a small (or none at all) amount of mocking
120+
- easily extendable
121+
- can be easily split into multiple packages
122+
- thanks to the `modules/*` approach with clear entrypoints (public interfaces) you can easily split this code to a separate npm package that could be reused in an another application
123+
- `shared/*` could also be split to a separate package
124+
125+
It's definitely not perfect and it might not be as scalable for a lot bigger projects (didn't had the opportunity to test it out in this kind of scenario yet), but it works fine in small-mid sizes ones for sure.
126+
127+
For bigger sized projects I'd definitely try out to integrate [https://nx.dev/](https://nx.dev/).

docs/assets/logo.jpg

122 KB
Loading

docs/assets/structure.png

201 KB
Loading

0 commit comments

Comments
 (0)