• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

elsewhencode/project-guidelines: A set of best practices for JavaScript projects

原作者: [db:作者] 来自: 网络 收藏 邀请

开源软件名称:

elsewhencode/project-guidelines

开源软件地址:

https://github.com/elsewhencode/project-guidelines

开源编程语言:

JavaScript 100.0%

开源软件介绍:

中文版 | 日本語版 | 한국어 | Русский | Português | Italiana

Project Guidelines · PRs Welcome

While developing a new project is like rolling on a green field for you, maintaining it is a potential dark twisted nightmare for someone else. Here's a list of guidelines we've found, written and gathered that (we think) works really well with most JavaScript projects here at elsewhen. If you want to share a best practice, or think one of these guidelines should be removed, feel free to share it with us.


1. Git

Git

1.1 Some Git rules

There are a set of rules to keep in mind:

  • Perform work in a feature branch.

    Why:

    Because this way all work is done in isolation on a dedicated branch rather than the main branch. It allows you to submit multiple pull requests without confusion. You can iterate without polluting the master branch with potentially unstable, unfinished code. read more...

  • Branch out from develop

    Why:

    This way, you can make sure that code in master will almost always build without problems, and can be mostly used directly for releases (this might be overkill for some projects).

  • Never push into develop or master branch. Make a Pull Request.

    Why:

    It notifies team members that they have completed a feature. It also enables easy peer-review of the code and dedicates forum for discussing the proposed feature.

  • Update your local develop branch and do an interactive rebase before pushing your feature and making a Pull Request.

    Why:

    Rebasing will merge in the requested branch (master or develop) and apply the commits that you have made locally to the top of the history without creating a merge commit (assuming there were no conflicts). Resulting in a nice and clean history. read more ...

  • Resolve potential conflicts while rebasing and before making a Pull Request.

  • Delete local and remote feature branches after merging.

    Why:

    It will clutter up your list of branches with dead branches. It ensures you only ever merge the branch back into (master or develop) once. Feature branches should only exist while the work is still in progress.

  • Before making a Pull Request, make sure your feature branch builds successfully and passes all tests (including code style checks).

    Why:

    You are about to add your code to a stable branch. If your feature-branch tests fail, there is a high chance that your destination branch build will fail too. Additionally, you need to apply code style check before making a Pull Request. It aids readability and reduces the chance of formatting fixes being mingled in with actual changes.

  • Use this .gitignore file.

    Why:

    It already has a list of system files that should not be sent with your code into a remote repository. In addition, it excludes setting folders and files for most used editors, as well as most common dependency folders.

  • Protect your develop and master branch.

    Why:

    It protects your production-ready branches from receiving unexpected and irreversible changes. read more... Github, Bitbucket and GitLab

1.2 Git workflow

Because of most of the reasons above, we use Feature-branch-workflow with Interactive Rebasing and some elements of Gitflow (naming and having a develop branch). The main steps are as follows:

  • For a new project, initialize a git repository in the project directory. For subsequent features/changes this step should be ignored.

    cd <project directory>
    git init
  • Checkout a new feature/bug-fix branch.

    git checkout -b <branchname>
  • Make Changes.

    git add <file1> <file2> ...
    git commit

    Why:

    git add <file1> <file2> ... - you should add only files that make up a small and coherent change.

    git commit will start an editor which lets you separate the subject from the body.

    Read more about it in section 1.3.

    Tip:

    You could use git add -p instead, which will give you chance to review all of the introduced changes one by one, and decide whether to include them in the commit or not.

  • Sync with remote to get changes you’ve missed.

    git checkout develop
    git pull

    Why:

    This will give you a chance to deal with conflicts on your machine while rebasing (later) rather than creating a Pull Request that contains conflicts.

  • Update your feature branch with latest changes from develop by interactive rebase.

    git checkout <branchname>
    git rebase -i --autosquash develop

    Why:

    You can use --autosquash to squash all your commits to a single commit. Nobody wants many commits for a single feature in develop branch. read more...

  • If you don’t have conflicts, skip this step. If you have conflicts, resolve them and continue rebase.

    git add <file1> <file2> ...
    git rebase --continue
  • Push your branch. Rebase will change history, so you'll have to use -f to force changes into the remote branch. If someone else is working on your branch, use the less destructive --force-with-lease.

    git push -f

    Why:

    When you do a rebase, you are changing the history on your feature branch. As a result, Git will reject normal git push. Instead, you'll need to use the -f or --force flag. read more...

  • Make a Pull Request.

  • Pull request will be accepted, merged and close by a reviewer.

  • Remove your local feature branch if you're done.

    git branch -d <branchname>

    to remove all branches which are no longer on remote

    git fetch -p && for branch in `git branch -vv --no-color | grep ': gone]' | awk '{print $1}'`; do git branch -D $branch; done

1.3 Writing good commit messages

Having a good guideline for creating commits and sticking to it makes working with Git and collaborating with others a lot easier. Here are some rules of thumb (source):

  • Separate the subject from the body with a newline between the two.

    Why:

    Git is smart enough to distinguish the first line of your commit message as your summary. In fact, if you try git shortlog, instead of git log, you will see a long list of commit messages, consisting of the id of the commit, and the summary only.

  • Limit the subject line to 50 characters and Wrap the body at 72 characters.

    why

    Commits should be as fine-grained and focused as possible, it is not the place to be verbose. read more...

  • Capitalize the subject line.

  • Do not end the subject line with a period.

  • Use imperative mood in the subject line.

    Why:

    Rather than writing messages that say what a committer has done. It's better to consider these messages as the instructions for what is going to be done after the commit is applied on the repository. read more...

  • Use the body to explain what and why as opposed to how.

2. Documentation

Documentation

  • Use this template for README.md, Feel free to add uncovered sections.
  • For projects with more than one repository, provide links to them in their respective README.md files.
  • Keep README.md updated as a project evolves.
  • Comment your code. Try to make it as clear as possible what you are intending with each major section.
  • If there is an open discussion on github or stackoverflow about the code or approach you're using, include the link in your comment.
  • Don't use comments as an excuse for a bad code. Keep your code clean.
  • Don't use clean code as an excuse to not comment at all.
  • Keep comments relevant as your code evolves.

3. Environments

Environments

  • Define separate development, test and production environments if needed.

    Why:

    Different data, tokens, APIs, ports etc... might be needed in different environments. You may want an isolated development mode that calls fake API which returns predictable data, making both automated and manual testing much easier. Or you may want to enable Google Analytics only on production and so on. read more...

  • Load your deployment specific configurations from environment variables and never add them to the codebase as constants, look at this sample.

    Why:

    You have tokens, passwords and other valuable information in there. Your config should be correctly separated from the app internals as if the codebase could be made public at any moment.

    How:

    .env files to store your variables and add them to .gitignore to be excluded. Instead, commit a .env.example which serves as a guide for developers. For production, you should still set your environment variables in the standard way. read more

  • It’s recommended to validate environment variables before your app starts. Look at this sample using joi to validate provided values. Why:

    It may save others from hours of troubleshooting.

3.1 Consistent dev environments:

  • Set your node version in engines in package.json.

    Why:

    It lets others know the version of node the project works on. read more...

  • Additionally, use nvm and create a .nvmrc in your project root. Don't forget to mention it in the documentation.

    Why:

    Any one who uses nvm can simply use nvm use to switch to the suitable node version. read more...

  • It's a good idea to setup a preinstall script that checks node and npm versions.

    Why:

    Some dependencies may fail when installed by newer versions of npm.

  • Use Docker image if you can.

    Why:

    It can give you a consistent environment across the entire workflow. Without much need to fiddle with dependencies or configs. read more...

  • Use local modules instead of using globally installed modules.

    Why:

    Lets you share your tooling with your colleague instead of expecting them to have it globally on their systems.

3.2 Consistent dependencies:

  • Make sure your team members get the exact same dependencies as you.

    Why:

    Because you want the code to behave as expected and identical in any development machine read more...

    how:

    Use package-lock.json on npm@5 or higher

    I don't have npm@5:

    Alternatively you can use Yarn and make sure to mention it in README.md. Your lock file and package.json should have the same versions after each dependency update. read more...

    I don't like the name Yarn:

    Too bad. For older versions of npm, use —save --save-exact when installing a new dependency and create npm-shrinkwrap.json before publishing. read more...

4. Dependencies

Github

  • Keep track of your currently available packages: e.g., npm ls --depth=0. read more...

  • See if any of your packages have become unused or irrelevant: depcheck. read more...

    Why:

    You may include an unused library in your code and increase the production bundle size. Find unused dependencies and get rid of them.

  • Before using a dependency, check its download statistics to see if it is heavily used by the community: npm-stat. read more...

    Why:

    More usage mostly means more contributors, which usually means better maintenance, and all of these result in quickly discovered bugs and quickly developed fixes.

  • Before using a dependency, check to see if it has a good, mature version release frequency with a large number of maintainers: e.g., npm view async. read more...

    Why:

    Having loads of contributors won't be as effective if maintainers don't merge fixes and patches quickly enough.

  • If a less known dependency is needed, discuss it with the team before using it.

  • Always make sure your app works with the latest version of its dependencies without breaking: npm outdated. read more...

    Why:

    Dependency updates sometimes contain breaking changes. Always check their release notes when updates show up. Update your dependencies one by one, that makes troubleshooting easier if anything goes wrong. Use a cool tool such as npm-check-updates.

  • Check to see if the package has known security vulnerabilities with, e.g., Snyk.

5. Testing

Testing

  • Have a test mode environment if needed.

    Why:

    While sometimes end to end testing in production mode might seem enough, there are some exceptions: One example is you may not want to enable analytical information on a 'production' mode and pollute someone's dashboard with test data. The other example is that your API may have rate limits in production and blocks your test calls after a certain amount of requests.

  • Place your test files next to the tested modules using *.test.js or *.spec.js naming convention, like moduleName.spec.js.

    Why:

    You don't want to dig through a folder structure to find a unit test. read more...

  • Put your additional test files into a separate test folder to avoid confusion.

    Why:

    Some test files don't particularly relate to any specific implementation file. You have to put it in a folder that is most likely to be found by other developers: __test__ folder. This name: __test__ is also standard now and gets picked up by most JavaScript testing frameworks.

  • Write testable code, avoid side effects, extract side effects, write pure functions

    Why:

    You want to test a business logic as separate units. You have to "minimize the impact of randomness and nondeterministic processes on the reliability of your code". read more...

    A pure function is a function that always returns the same output for the same input. Conversely, an impure function is one that may have side effects or depends on conditions from the outside to produce a value. That makes it less predictable. read more...

  • Use a static type checker

    Why:

    Sometimes you may need a Static type checker. It brings a certain level of reliability to your code. read more...

  • Run tests locally before making any pull requests to develop.

    Why:

    You don't want to be the one who caused production-ready branch build to fail. Run your tests after your rebase and before pushing your feature-branch to a remote repository.

  • Document your tests including instructions in the relevant section of your README.md file.

    Why:

    It's a handy note you leave behind for other developers or DevOps experts or QA or anyone who gets lucky enough to work on your code.

6. Structure and Naming

Structure and Naming

  • Organize your files around product features / pages / components, not roles. Also, place your test files next to their implementation.

    Bad

    .
    ├── controllers
    |   ├── product.js
    |   └── user.js
    ├── models
    |   ├── product.js
    |   └── user.js
    

    Good

    .
    ├── product
    |   ├── index.js
    |   ├── product.js
    |   └── product.test.js
    ├── user
    |   ├── index.js
    |   ├── user.js
    |   └── user.test.js
    

    Why:

    Instead of a long list of files, you will create small modules that encapsulate one responsibility including its test and so on. It gets much easier to navigate through and things can be found at a glance.

  • Put your additional test files to a separate test folder to avoid confusion.

    Why:

    It is a time saver for other developers or DevOps experts in your team.

  • Use a ./config folder and don't make different config files for different environments.

    Why:

    When you break down a config file for different purposes (database, API and so on); putting them in a folder with a very recognizable name such as config makes sense. Just remember not to make different config files for different environments. It doesn't scale cleanly, as more deploys of the app are created, new environment names are necessary. Values to be used in config files should be provided by environment variables. read more...

  • Put your scripts in a ./scripts folder. This includes bash and node scripts.

    Why:

    It's very likely you may end up with more than one script, production build, development build, database feeders, database synchronization and so on.

  • Place your build output in a ./build folder. Add build/ to .gitignore.

    Why:

    Name it what you like, dist is also cool. But make sure that keep it consistent with your team. What gets in there is most likely generated (bundled, compiled, transpiled) or moved there. What you can generate, your teammates should be able to generate too, so there is no point committing them into your remote repository. Unless you specifically want to.

7. Code style

Code style

7.1 Some code style guidelines

  • Use stage-2 and higher JavaScript (modern) syntax for new projects. For old project stay consistent with existing syntax unless you intend to modernise the project.

    Why:

    This is all up to you. We use transpilers to use advantages of new syntax. stage-2 is more likely to eventually become part of the spec with only minor revisions.

  • Include code style check in your build process.

    Why:

    Breaking your build is one way of enforcing code style to your code. It prevents you from taking it less seriously. Do it for both client and server-side code. read more...

  • Use ESLint - Pluggable JavaScript linter to enforce code style.

    Why:

    We simply prefer eslint, you don't have to. It has more rules supported, the ability to configure the rules, and ability to add custom rules.

  • We use Airbnb JavaScript Style Guide for JavaScript, Read more. Use the javascript style guide required by the project or your team.

  • We use Flow type style check rules for ESLint when using FlowType.

    Why:

    Flow introduces few syntaxes that also need to follow certain code style and be checked.

  • Use .eslintignore to exclude files or folders from code style checks.

    Why:

    You don't have to pollute your code with eslint-disable comments whenever you need to exclude a couple of files from style checking.

  • Remove any of your eslint disable comments before making a Pull Request.

    Why:

    It's normal to disable style check while working on a code block to focus more on the logic. Just remember to remove those eslint-disable comments and follow the rules.

  • Depending on the size of the task use //TODO: comments or open a ticket.

    Why:

    So then you can remind yourself and others about a small task (like refactoring a function or updating a comment). For larger tasks use //TODO(#3456) which is enforced by a lint rule and the number is an open ticket.

  • Always comment and keep them relevant as code changes. Remove commented blocks of code.

    Why:

    Your code should be as readable as possible, you should get rid of anything distracting. If you refactored a function, don't just comment out the old one, remove it.

  • Avoid irrelevant or funny comments, logs or naming.

    Why:

    While your build process may(should) get rid of them, sometimes your source code may get handed over to another company/client and they may not share the same banter.

  • Make your names search-able with meaningful distinctions avoid shortened names. For functions use long, descriptive names. A function name should be a verb or a verb phrase, and it needs to communicate its intention.

    Why:

    It makes it more natural to read the source code.

  • Organize your functions in a file according to the step-down rule. Higher level functions should be on top and lower levels below.

    Why:

    It makes it more natural to read the source code.

7.2 Enforcing code style standards

  • Use a .editorconfig file which helps developers define and maintain consistent coding styles between different editors and IDEs on the project.

    Why:

    The EditorConfig project consists of a file format for defining coding styles and a collection of text editor plugins that enable editors to read the file format and adhere to defined styles. EditorConfig files are easily readable and they work nicely with version control systems.

  • Have your editor notify you about code style errors. Use eslint-plugin-prettier and eslint-config-prettier with your existing ESLint configuration. read more...

  • Consider using Git hooks.

    Why:

    Git hooks greatly increase a developer's productivity. Make changes, commit and push to staging or production environments without the fear of breaking builds. read more...

  • Use Prettier with a precommit hook.

    Why:

    While prettier itself can be very powerful, it's not very productive to run it simply as an npm task alone each time to format code. This is where lint-staged (and husky) come into play. Read more on configuring lint-staged here and on configuring husky here.

8. Logging

Logging

  • Avoid client-side console logs in production

    Why:

    Even though your build process can (should) get rid of them, make sure that your code style checker warns you about leftover console logs.

  • Produce readable production logging. Ideally use logging libraries to be used in production mode (such as winston or node-bunyan).

    _Why:_
    > It makes your troubleshooting less unpleasant with colorization, timestamps, log to a file in addition to the console or even logging to a file that rotates daily. [read more...](https://blog.risingstack.com/node-js-logging-tutorial/)
    

9. API

API

9.1 API design

Why:

Because we try to enforce development of sanely constructed RESTful interfaces, which team members and clients can consume simply and consistently.

Why:

Lack of consistency and simplicity can massively increase integration and maintenance costs. Which is why API design is included in this document.