Habits is an application created to track activities in order to form real-life habits.
- Habits
- Version Control: We use git as our version control system, and we use git-flow.
- Package Manager: We use several javascript packages and we prefer using Yarn over npm to manage our dependencies. Therefore in this project there should only be a
yarn.lock
file, and not apackage-lock.json
file. - Development: We are using React. This project was bootstrapped with Create React App. You can learn more about Create React App on this copy of the project README.md.
- Linting: We are using eslint to lint our code. Eslint is a pluggable linting utility for JavaScript to keep our codebase written consistently. We are extending from Airbnb configuration. We are also using stylelint, which is a mighty, modern linter that helps us avoid errors and enforce conventions in our styles.
- Code formatter: In order to keep our codebase written consistently, and reducing the feedback loop for linting errors we are using Prettier as our code formatter. Prettier is an opinionated code formatter with support for JavaScript, CSS and JSON. With Prettier you can format the code you write automatically to ensure a code style within your project.
- Styling: We are using ITCSS. You can read more about how we are implementing it here.
- Testing: We require to have great code coverage with meaningful tests. As we are using Create React App, and most of our code will be written with JavasSript, we are usign Jest as our testing framework. We are also using [React Testing Library][react-testing-library] to help us test the UI components.
- Routing: We are using Reach Router, a small, simple router for React. Reach Router has a small footprint, supports only simple route patterns by design, and has strong accessibility features. We decided to pass on React Router because of [this announcement][react_router_announcement] found on the React Router documentation page. When the React Router v6.0.0 is finally out, we could evaluate on switching to that router.
- Deployments: We will be using Firebase hosting for
dev
, andstaging
.
For a breif explanation of what is being install, please read our setup documentation.
To install all our dependencies on a OSX, run scripts/setup.osx.sh
.
To install all our dependencies on Ubuntu, run scripts/setup.ubuntu.sh
.
It is recommended to run the setup script everytime you pull from the develop
branch. This way you can always be sure to have all the project dependencies up to date.
EditorConfig helps to maintain consistent coding styles for all developers working on the project across various editors and IDEs. We have this configured in our .editorconfig file. Make sure to configure your editor or IDE.
One of our dependencies is Prettier. Prettier is an opinionated code formatter for our codebase. Prettier works best by enabling its format on document save. In order to do this in vscode you need to install this eslint extension, and configure the IDE. We already have this configured in the .vscode/settings.json file.
We have configured to debugg our app on Chrome. In order to do this you need to install this Debugger for Chrome extension on your vscode, and configure the IDE. We already have this configured in the /.vscode/launch.json file. With this you could use some breakpoints and debug the app on the IDE, and Chrome.
We are using eslint
, and stylelint
to make static analysis to find problematic patterns and make sure all the team adhere to certain style guidelines. We like a lot the Airbnb guidelines for Javascript and React.
This is already configured in the eslintrc.js and stylelintrc.js files.
We have configured eslint
, and stylelint
with webpack to make sure that we get all the linting information during the development. However, if you want to lint the project you could use the following commands.
To lint all the .js
files run the command:
yarn lint:js
This will prompt all the errors and warnings of the code that is not following our coding conventions. Most of the linting problems can be fixed by eslint. To fix those kind of issues run:
yarn lint:js-fix
To lint all the .scss
files run the command:
yarn lint:scss
This will prompt all the errors and warnings of the code that is not following our coding conventions. Most of the linting problems can be fixed by eslint. To fix those kind of issues run:
yarn lint:scss-fix
To lint with both eslint
, and stylelint
run the command:
yarn lint
To lint and fix with both eslint
, and stylelint
run the command:
yarn lint-fix
Additionally, there is a script configured to prevent us from commiting files with linting issues. Whenever you try to make a commit, the linting will run and prevent the commit if there is an issue with the code.
We are using jest to make our unit testing. This is already configured on our package.json file on the key jest
.
Jest is a Node-based runner. This means that the tests always run in a Node environment and not in a real browser. This lets us enable fast iteration speed and prevent flakiness.
While Jest provides browser globals such as window thanks to jsdom, they are only approximations of the real browser behavior. Jest is intended to be used for unit tests of your logic and your components rather than the DOM quirks.
Jest will look for test files with any of the following popular naming conventions:
- Files with
.js
suffix in tests folders. - Files with
.test.js
suffix. - Files with
.spec.js
suffix.
The .test.js
/ .spec.js
files (or the tests folders) can be located at any depth under the src
top level folder.
However, we should put the test files next to the code they are testing so that relative imports appear shorter. For example, if App.test.js
and App.js
are in the same folder, the test only needs to import App from './App'
instead of a long relative path. Collocation also helps find tests more quickly.
To run all our tests run the command:
yarn test
We are striving to keep the following benchmarks:
- Statements coverage — 75%.
- Branches coverage — 75%.
- Lines coverage — 75%.
- Functions coverage — 75%.
To find out the current coverage of the whole project run the command:
yarn test:coverage
We recommend to develop with a Test Driven Development mindset, therefore, we recommend running the following command while developing:
yarn test:watch
The watcher includes an interactive command-line interface with the ability to run all tests, or focus on a search pattern. It is designed this way so that you can keep it open and enjoy fast re-runs.
If you want to debug your tests, you can do it by writing debugger;
statements in any test and running the following command:
yarn test:debug
This will start running your Jest tests, but pause before executing to allow a debugger to attach to the process.
For a more detailed explanation of our testing conventions, please read our testing guidelines.
We've decided to wrap third-party dependencies into custom abstractions. As this thread explains, the wrapped dependency is isolated, and if a change in the API of that dependency changes, there is only one change point in our codebase (making sure you respect the interface).
If we let a dependency "invade" our code, we're inevitably going to couple the entire application to it. This means that we'll make choices that lean towards making the library happy, and end up with code which requires a significant cognitive overhead.
In the OOP world, this is known as the bridge pattern. The goal is to:
Decouple an abstraction from its implementation so that the two can vary independently.
For most third-party dependencies there should be a dedicated directory under the dependencies
directory. On most cases this directory should keep the same name as the dependency that is going to be wrapped.
There is a few exceptions for using the bridge pattern:
react
prop-types
@testing-library/react
After all, we are making a React project, and these are the core libraries that we are using. If the API of these dependencies changes, then we should update our codebase accordingly.
Some abstractions are really important and we would have it's own directory inside src
:
router
It's relevant to note that we refer to dependencies to everything that imposes an API foreign to our codebase logic.
This will provide us with the flexibility to work with a specific dependency without compromising our implementation to that.
For instance, if we are working with the native Fetch API. Maybe we made that choice a while ago because that was enough. If the application starts growing, we might need to cover more use cases. Then, we could decide that it's time to move to something like Axios.
If we've leaked the usage of Fetch everywhere, we would be up for a nasty refactor. Not only we are changing an implementation, but now we must also go to every single place we've used it. A targeted, focused change is now having a domino effect on the entire app.
On the other hand, if we've wrapped Fetch in an abstraction that makes sense for our app, then we've isolated its usage. Maybe we pre-filled it with sensible defaults, and specialized into a module that anyone with domain knowledge of the app can understand.
Make sure to be have access to the Firebase project. If you don't have access, and want to collaborate, please reach the administrator of this project.
- Install Firebase CLI:
npm install -g firebase-tools
- Login into Firebase:
firebase login
We will be using Firebase hosting for dev
, and qa
.
To deploy the project to the dev
environment just run the command yarn deploy:dev
.
To deploy the project to the staging
environment just run the command yarn deploy:staging
.
Please read through our contributing guidelines. Included are directions for opening issues, coding standards, and notes on development.
- We use git-flow to create new features. For further information read this guide.
- Create a [Pull Request][pull_requests] and assign a relevant reviewer.
- Fix pull request comments (when necessary).
- Finish your feature with
git flow feature finish <feature_branch>
and push to thedevelop
branch.