2016-06-26 18:49:35 +02:00
|
|
|
# Code style and conventions
|
2016-05-15 18:28:38 +02:00
|
|
|
|
2023-05-23 17:15:33 +02:00
|
|
|
This page documents code style policies that every Zulip developer
|
|
|
|
should understand. We aim for this document to be short and focused
|
|
|
|
only on details that cannot be easily enforced another way (e.g.,
|
|
|
|
through linters, automated tests, or subsystem design that makes classes
|
|
|
|
of mistakes unlikely). This approach minimizes the cognitive
|
|
|
|
load of ensuring a consistent coding style for both contributors and
|
|
|
|
maintainers.
|
|
|
|
|
2020-06-08 11:33:04 +02:00
|
|
|
One can summarize Zulip's coding philosophy as a relentless focus on
|
2020-05-19 23:22:15 +02:00
|
|
|
making the codebase easy to understand and difficult to make dangerous
|
2023-05-23 17:15:33 +02:00
|
|
|
mistakes in (see the sections on [dangerous constructs](#dangerous-constructs-in-django)
|
|
|
|
at the end of this page). The majority of work in any large software
|
|
|
|
development project is understanding the existing code so one can debug
|
|
|
|
or modify it, and investments in code readability usually end up paying
|
|
|
|
for themselves when someone inevitably needs to debug or improve the code.
|
2020-05-19 23:22:15 +02:00
|
|
|
|
|
|
|
When there's something subtle or complex to explain or ensure in the
|
2023-05-23 17:15:33 +02:00
|
|
|
implementation, we try hard to make it clear through a combination of
|
2020-05-19 23:22:15 +02:00
|
|
|
clean and intuitive interfaces, well-named variables and functions,
|
2023-05-23 17:15:33 +02:00
|
|
|
comments/docstrings, and commit messages (roughly in that order of
|
|
|
|
priority -- if you can make something clear with a good interface,
|
|
|
|
that's a lot better than writing a comment explaining how the bad
|
|
|
|
interface works).
|
2020-05-19 23:22:15 +02:00
|
|
|
|
2023-05-23 17:15:33 +02:00
|
|
|
After an introduction to our lint tools and test suites, this document
|
|
|
|
outlines some general
|
|
|
|
[conventions and practices](#follow-zulip-conventions-and-practices)
|
|
|
|
applicable to all languages used in the codebase, as well as specific
|
|
|
|
guidance on [Python](#python-specific-conventions-and-practices) and
|
|
|
|
[JavaScript and TypeScript](#javascript-and-typescript-conventions-and-practices).
|
2023-05-19 22:23:29 +02:00
|
|
|
([HTML and CSS](../subsystems/html-css.md) are outlined in their own
|
|
|
|
documentation.)
|
2023-05-23 17:15:33 +02:00
|
|
|
|
|
|
|
At the end of the document, you can read about
|
|
|
|
[dangerous constructs in Django](#dangerous-constructs-in-django) and
|
|
|
|
[JavaScript and TypeScript](#dangerous-constructs-in-javascript-and-typescript)
|
|
|
|
that you should absolutely avoid.
|
2020-05-19 23:22:15 +02:00
|
|
|
|
2023-05-22 22:22:19 +02:00
|
|
|
## Be consistent with existing code
|
2016-05-15 18:28:38 +02:00
|
|
|
|
|
|
|
Look at the surrounding code, or a similar part of the project, and try
|
|
|
|
to do the same thing. If you think the other code has actively bad
|
|
|
|
style, fix it (in a separate commit).
|
|
|
|
|
2021-11-18 07:25:55 +01:00
|
|
|
When in doubt, ask in
|
|
|
|
[#development help](https://chat.zulip.org/#narrow/stream/49-development-help).
|
2016-05-15 18:28:38 +02:00
|
|
|
|
2023-05-22 22:22:19 +02:00
|
|
|
### Use the linters
|
2016-05-15 18:28:38 +02:00
|
|
|
|
2023-05-23 17:24:36 +02:00
|
|
|
You can run all of the linters at once:
|
2016-05-15 18:28:38 +02:00
|
|
|
|
2021-08-20 07:09:04 +02:00
|
|
|
```bash
|
2023-05-23 17:24:36 +02:00
|
|
|
$ ./tools/lint
|
2021-08-20 07:09:04 +02:00
|
|
|
```
|
2016-05-15 18:28:38 +02:00
|
|
|
|
2023-05-23 17:24:36 +02:00
|
|
|
Note that that takes a little time. `./tools/lint` runs many
|
|
|
|
lint checks in parallel, including:
|
2016-05-15 18:28:38 +02:00
|
|
|
|
2021-08-20 22:54:08 +02:00
|
|
|
- JavaScript ([ESLint](https://eslint.org/),
|
|
|
|
[Prettier](https://prettier.io/))
|
|
|
|
- Python ([mypy](http://mypy-lang.org/),
|
2023-10-27 00:19:05 +02:00
|
|
|
[ruff](https://github.com/astral-sh/ruff),
|
2021-08-20 22:54:08 +02:00
|
|
|
[Black](https://github.com/psf/black),
|
|
|
|
[isort](https://pycqa.github.io/isort/))
|
|
|
|
- templates
|
|
|
|
- Puppet configuration
|
2023-05-23 17:24:36 +02:00
|
|
|
- custom checks (e.g., trailing whitespace and spaces-not-tabs)
|
|
|
|
|
|
|
|
To speed things up, you can [pass specific files or directories
|
|
|
|
to the linter](../testing/linters.md):
|
|
|
|
|
|
|
|
```
|
|
|
|
$ ./tools/lint web/src/compose.js
|
|
|
|
```
|
|
|
|
|
|
|
|
If you'd like, you can also set up a local Git commit hook that
|
|
|
|
will lint only your changed files each time you commit:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
$ ./tools/setup-git-repo
|
|
|
|
```
|
2016-05-15 18:28:38 +02:00
|
|
|
|
2023-05-22 22:22:19 +02:00
|
|
|
### Use tests to verify your logic
|
docs: Reorganize code style and conventions doc.
This commit represents an in-place reordering of the document. No
headings or content has been changed (that will happen in subsequent
commits).
The goal is to open the document with generic advice and guidance
applicable to all Zulip developers across all languages:
1. Consistency, enforced by linters and automated tests, opens the
document.
2. General, largely language-neutral advice about line length,
third-party code, translation, paths, and secrets come next.
3. Next up is language-specific advice and conventions: Python,
followed by JavaScript and TypeScript, followed by HTML and CSS
(although the HTML and CSS will be moved in a subsequent commit
to their own file).
4. Closing the file, rather than opening it, is the section on
Dangerous constructs. Some of these are fairly specialized, so
it makes sense not to ask readers to read through them before
presenting, say, our philosophy on line length.
Finally, in trying to come up with a sensible order for all sections
of this document, the "More arbitrary style things" heading has been
removed.
2023-05-22 22:06:13 +02:00
|
|
|
|
|
|
|
Clear, readable code is important for [tests](../testing/testing.md);
|
2023-05-24 19:26:14 +02:00
|
|
|
familiarize yourself with our
|
|
|
|
[testing frameworks](../testing/testing.md#major-test-suites) and
|
|
|
|
[testing philosophy](../testing/philosophy.md) so that you can write
|
2023-05-23 17:24:36 +02:00
|
|
|
clean, readable tests. In-test comments about anything subtle that is
|
docs: Reorganize code style and conventions doc.
This commit represents an in-place reordering of the document. No
headings or content has been changed (that will happen in subsequent
commits).
The goal is to open the document with generic advice and guidance
applicable to all Zulip developers across all languages:
1. Consistency, enforced by linters and automated tests, opens the
document.
2. General, largely language-neutral advice about line length,
third-party code, translation, paths, and secrets come next.
3. Next up is language-specific advice and conventions: Python,
followed by JavaScript and TypeScript, followed by HTML and CSS
(although the HTML and CSS will be moved in a subsequent commit
to their own file).
4. Closing the file, rather than opening it, is the section on
Dangerous constructs. Some of these are fairly specialized, so
it makes sense not to ask readers to read through them before
presenting, say, our philosophy on line length.
Finally, in trying to come up with a sensible order for all sections
of this document, the "More arbitrary style things" heading has been
removed.
2023-05-22 22:06:13 +02:00
|
|
|
being verified are appreciated.
|
|
|
|
|
2023-05-24 19:26:14 +02:00
|
|
|
You can run all of the tests like this:
|
|
|
|
|
|
|
|
```
|
|
|
|
$ ./tools/test-all
|
|
|
|
```
|
|
|
|
|
|
|
|
But consult [our documentation on running tests](../testing/testing.md#running-tests),
|
|
|
|
which covers more targeted approaches to commanding the test-runners.
|
|
|
|
|
2023-05-22 22:22:19 +02:00
|
|
|
## Follow Zulip conventions and practices
|
|
|
|
|
|
|
|
What follows is language-neutral advice that is beyond the bounds of
|
|
|
|
linters and automated tests.
|
|
|
|
|
|
|
|
### Observe a reasonable line length
|
docs: Reorganize code style and conventions doc.
This commit represents an in-place reordering of the document. No
headings or content has been changed (that will happen in subsequent
commits).
The goal is to open the document with generic advice and guidance
applicable to all Zulip developers across all languages:
1. Consistency, enforced by linters and automated tests, opens the
document.
2. General, largely language-neutral advice about line length,
third-party code, translation, paths, and secrets come next.
3. Next up is language-specific advice and conventions: Python,
followed by JavaScript and TypeScript, followed by HTML and CSS
(although the HTML and CSS will be moved in a subsequent commit
to their own file).
4. Closing the file, rather than opening it, is the section on
Dangerous constructs. Some of these are fairly specialized, so
it makes sense not to ask readers to read through them before
presenting, say, our philosophy on line length.
Finally, in trying to come up with a sensible order for all sections
of this document, the "More arbitrary style things" heading has been
removed.
2023-05-22 22:06:13 +02:00
|
|
|
|
|
|
|
We have an absolute hard limit on line length only for some files, but
|
|
|
|
we should still avoid extremely long lines. A general guideline is:
|
|
|
|
refactor stuff to get it under 85 characters, unless that makes the
|
|
|
|
code a lot uglier, in which case it's fine to go up to 120 or so.
|
|
|
|
|
2023-05-22 22:22:19 +02:00
|
|
|
### Tag user-facing strings for translation
|
docs: Reorganize code style and conventions doc.
This commit represents an in-place reordering of the document. No
headings or content has been changed (that will happen in subsequent
commits).
The goal is to open the document with generic advice and guidance
applicable to all Zulip developers across all languages:
1. Consistency, enforced by linters and automated tests, opens the
document.
2. General, largely language-neutral advice about line length,
third-party code, translation, paths, and secrets come next.
3. Next up is language-specific advice and conventions: Python,
followed by JavaScript and TypeScript, followed by HTML and CSS
(although the HTML and CSS will be moved in a subsequent commit
to their own file).
4. Closing the file, rather than opening it, is the section on
Dangerous constructs. Some of these are fairly specialized, so
it makes sense not to ask readers to read through them before
presenting, say, our philosophy on line length.
Finally, in trying to come up with a sensible order for all sections
of this document, the "More arbitrary style things" heading has been
removed.
2023-05-22 22:06:13 +02:00
|
|
|
|
|
|
|
Remember to
|
2023-05-23 17:24:36 +02:00
|
|
|
[tag all user-facing strings for translation](../translating/translating.md),
|
|
|
|
whether the strings are in HTML templates or output by JavaScript/TypeScript
|
|
|
|
that injects or modifies HTML (e.g., error messages).
|
docs: Reorganize code style and conventions doc.
This commit represents an in-place reordering of the document. No
headings or content has been changed (that will happen in subsequent
commits).
The goal is to open the document with generic advice and guidance
applicable to all Zulip developers across all languages:
1. Consistency, enforced by linters and automated tests, opens the
document.
2. General, largely language-neutral advice about line length,
third-party code, translation, paths, and secrets come next.
3. Next up is language-specific advice and conventions: Python,
followed by JavaScript and TypeScript, followed by HTML and CSS
(although the HTML and CSS will be moved in a subsequent commit
to their own file).
4. Closing the file, rather than opening it, is the section on
Dangerous constructs. Some of these are fairly specialized, so
it makes sense not to ask readers to read through them before
presenting, say, our philosophy on line length.
Finally, in trying to come up with a sensible order for all sections
of this document, the "More arbitrary style things" heading has been
removed.
2023-05-22 22:06:13 +02:00
|
|
|
|
2023-05-22 22:22:19 +02:00
|
|
|
### Correctly prepare paths destined for state or log files
|
docs: Reorganize code style and conventions doc.
This commit represents an in-place reordering of the document. No
headings or content has been changed (that will happen in subsequent
commits).
The goal is to open the document with generic advice and guidance
applicable to all Zulip developers across all languages:
1. Consistency, enforced by linters and automated tests, opens the
document.
2. General, largely language-neutral advice about line length,
third-party code, translation, paths, and secrets come next.
3. Next up is language-specific advice and conventions: Python,
followed by JavaScript and TypeScript, followed by HTML and CSS
(although the HTML and CSS will be moved in a subsequent commit
to their own file).
4. Closing the file, rather than opening it, is the section on
Dangerous constructs. Some of these are fairly specialized, so
it makes sense not to ask readers to read through them before
presenting, say, our philosophy on line length.
Finally, in trying to come up with a sensible order for all sections
of this document, the "More arbitrary style things" heading has been
removed.
2023-05-22 22:06:13 +02:00
|
|
|
|
|
|
|
When writing out state or log files, always pass an absolute path
|
|
|
|
through `zulip_path` (found in `zproject/computed_settings.py`), which
|
|
|
|
will do the right thing in both development and production.
|
|
|
|
|
2023-05-22 22:22:19 +02:00
|
|
|
### Never include secrets inline with code
|
2016-05-15 18:28:38 +02:00
|
|
|
|
|
|
|
Please don't put any passwords, secret access keys, etc. inline in the
|
2022-08-25 21:26:41 +02:00
|
|
|
code. Instead, use the `get_secret` function or the `get_mandatory_secret`
|
|
|
|
function in `zproject/config.py` to read secrets from `/etc/zulip/secrets.conf`.
|
2016-05-15 18:28:38 +02:00
|
|
|
|
2023-05-22 22:22:19 +02:00
|
|
|
### Familiarize yourself with rules about third-party code
|
|
|
|
|
|
|
|
See [our docs on dependencies](../subsystems/dependencies.md) for discussion of
|
|
|
|
rules about integrating third-party projects.
|
|
|
|
|
|
|
|
## Python-specific conventions and practices
|
docs: Reorganize code style and conventions doc.
This commit represents an in-place reordering of the document. No
headings or content has been changed (that will happen in subsequent
commits).
The goal is to open the document with generic advice and guidance
applicable to all Zulip developers across all languages:
1. Consistency, enforced by linters and automated tests, opens the
document.
2. General, largely language-neutral advice about line length,
third-party code, translation, paths, and secrets come next.
3. Next up is language-specific advice and conventions: Python,
followed by JavaScript and TypeScript, followed by HTML and CSS
(although the HTML and CSS will be moved in a subsequent commit
to their own file).
4. Closing the file, rather than opening it, is the section on
Dangerous constructs. Some of these are fairly specialized, so
it makes sense not to ask readers to read through them before
presenting, say, our philosophy on line length.
Finally, in trying to come up with a sensible order for all sections
of this document, the "More arbitrary style things" heading has been
removed.
2023-05-22 22:06:13 +02:00
|
|
|
|
|
|
|
- Our Python code is formatted with
|
|
|
|
[Black](https://github.com/psf/black) and
|
|
|
|
[isort](https://pycqa.github.io/isort/). The [linter
|
|
|
|
tool](../testing/linters.md) enforces this by running Black and
|
|
|
|
isort in check mode, or in write mode with
|
|
|
|
`tools/lint --only=black,isort --fix`. You may find it helpful to
|
2023-05-23 17:37:36 +02:00
|
|
|
[integrate Black](https://black.readthedocs.io/en/stable/integrations/editors.html)
|
docs: Reorganize code style and conventions doc.
This commit represents an in-place reordering of the document. No
headings or content has been changed (that will happen in subsequent
commits).
The goal is to open the document with generic advice and guidance
applicable to all Zulip developers across all languages:
1. Consistency, enforced by linters and automated tests, opens the
document.
2. General, largely language-neutral advice about line length,
third-party code, translation, paths, and secrets come next.
3. Next up is language-specific advice and conventions: Python,
followed by JavaScript and TypeScript, followed by HTML and CSS
(although the HTML and CSS will be moved in a subsequent commit
to their own file).
4. Closing the file, rather than opening it, is the section on
Dangerous constructs. Some of these are fairly specialized, so
it makes sense not to ask readers to read through them before
presenting, say, our philosophy on line length.
Finally, in trying to come up with a sensible order for all sections
of this document, the "More arbitrary style things" heading has been
removed.
2023-05-22 22:06:13 +02:00
|
|
|
and
|
|
|
|
[isort](https://pycqa.github.io/isort/#installing-isorts-for-your-preferred-text-editor)
|
|
|
|
with your editor.
|
|
|
|
- Don't put a shebang line on a Python file unless it's meaningful to
|
2023-05-23 17:37:36 +02:00
|
|
|
run it as a script. (Some libraries can also be run as scripts, e.g.,
|
docs: Reorganize code style and conventions doc.
This commit represents an in-place reordering of the document. No
headings or content has been changed (that will happen in subsequent
commits).
The goal is to open the document with generic advice and guidance
applicable to all Zulip developers across all languages:
1. Consistency, enforced by linters and automated tests, opens the
document.
2. General, largely language-neutral advice about line length,
third-party code, translation, paths, and secrets come next.
3. Next up is language-specific advice and conventions: Python,
followed by JavaScript and TypeScript, followed by HTML and CSS
(although the HTML and CSS will be moved in a subsequent commit
to their own file).
4. Closing the file, rather than opening it, is the section on
Dangerous constructs. Some of these are fairly specialized, so
it makes sense not to ask readers to read through them before
presenting, say, our philosophy on line length.
Finally, in trying to come up with a sensible order for all sections
of this document, the "More arbitrary style things" heading has been
removed.
2023-05-22 22:06:13 +02:00
|
|
|
to run a test suite.)
|
|
|
|
- Scripts should be executed directly (`./script.py`), so that the
|
|
|
|
interpreter is implicitly found from the shebang line, rather than
|
|
|
|
explicitly overridden (`python script.py`).
|
|
|
|
- Put all imports together at the top of the file, absent a compelling
|
|
|
|
reason to do otherwise.
|
|
|
|
- Unpacking sequences doesn't require list brackets:
|
|
|
|
```python
|
|
|
|
[x, y] = xs # unnecessary
|
|
|
|
x, y = xs # better
|
|
|
|
```
|
|
|
|
- For string formatting, use `x % (y,)` rather than `x % y`, to avoid
|
|
|
|
ambiguity if `y` happens to be a tuple.
|
|
|
|
|
2023-05-22 22:22:19 +02:00
|
|
|
## JavaScript and TypeScript conventions and practices
|
docs: Reorganize code style and conventions doc.
This commit represents an in-place reordering of the document. No
headings or content has been changed (that will happen in subsequent
commits).
The goal is to open the document with generic advice and guidance
applicable to all Zulip developers across all languages:
1. Consistency, enforced by linters and automated tests, opens the
document.
2. General, largely language-neutral advice about line length,
third-party code, translation, paths, and secrets come next.
3. Next up is language-specific advice and conventions: Python,
followed by JavaScript and TypeScript, followed by HTML and CSS
(although the HTML and CSS will be moved in a subsequent commit
to their own file).
4. Closing the file, rather than opening it, is the section on
Dangerous constructs. Some of these are fairly specialized, so
it makes sense not to ask readers to read through them before
presenting, say, our philosophy on line length.
Finally, in trying to come up with a sensible order for all sections
of this document, the "More arbitrary style things" heading has been
removed.
2023-05-22 22:06:13 +02:00
|
|
|
|
|
|
|
Our JavaScript and TypeScript code is formatted with
|
|
|
|
[Prettier](https://prettier.io/). You can ask Prettier to reformat
|
|
|
|
all code via our [linter tool](../testing/linters.md) with
|
|
|
|
`tools/lint --only=prettier --fix`. You can also [integrate it with your
|
|
|
|
editor](https://prettier.io/docs/en/editors.html).
|
|
|
|
|
2023-05-23 17:37:51 +02:00
|
|
|
### Build DOM elements in Handlebars
|
docs: Reorganize code style and conventions doc.
This commit represents an in-place reordering of the document. No
headings or content has been changed (that will happen in subsequent
commits).
The goal is to open the document with generic advice and guidance
applicable to all Zulip developers across all languages:
1. Consistency, enforced by linters and automated tests, opens the
document.
2. General, largely language-neutral advice about line length,
third-party code, translation, paths, and secrets come next.
3. Next up is language-specific advice and conventions: Python,
followed by JavaScript and TypeScript, followed by HTML and CSS
(although the HTML and CSS will be moved in a subsequent commit
to their own file).
4. Closing the file, rather than opening it, is the section on
Dangerous constructs. Some of these are fairly specialized, so
it makes sense not to ask readers to read through them before
presenting, say, our philosophy on line length.
Finally, in trying to come up with a sensible order for all sections
of this document, the "More arbitrary style things" heading has been
removed.
2023-05-22 22:06:13 +02:00
|
|
|
|
|
|
|
The best way to build complicated DOM elements is a Handlebars template
|
2023-05-23 17:37:51 +02:00
|
|
|
like `web/templates/message_reactions.hbs`. For simpler things you can
|
|
|
|
use jQuery DOM-building APIs like this:
|
docs: Reorganize code style and conventions doc.
This commit represents an in-place reordering of the document. No
headings or content has been changed (that will happen in subsequent
commits).
The goal is to open the document with generic advice and guidance
applicable to all Zulip developers across all languages:
1. Consistency, enforced by linters and automated tests, opens the
document.
2. General, largely language-neutral advice about line length,
third-party code, translation, paths, and secrets come next.
3. Next up is language-specific advice and conventions: Python,
followed by JavaScript and TypeScript, followed by HTML and CSS
(although the HTML and CSS will be moved in a subsequent commit
to their own file).
4. Closing the file, rather than opening it, is the section on
Dangerous constructs. Some of these are fairly specialized, so
it makes sense not to ask readers to read through them before
presenting, say, our philosophy on line length.
Finally, in trying to come up with a sensible order for all sections
of this document, the "More arbitrary style things" heading has been
removed.
2023-05-22 22:06:13 +02:00
|
|
|
|
|
|
|
```js
|
2023-05-23 17:37:51 +02:00
|
|
|
const $new_tr = $('<tr />').attr('id', object.id);
|
docs: Reorganize code style and conventions doc.
This commit represents an in-place reordering of the document. No
headings or content has been changed (that will happen in subsequent
commits).
The goal is to open the document with generic advice and guidance
applicable to all Zulip developers across all languages:
1. Consistency, enforced by linters and automated tests, opens the
document.
2. General, largely language-neutral advice about line length,
third-party code, translation, paths, and secrets come next.
3. Next up is language-specific advice and conventions: Python,
followed by JavaScript and TypeScript, followed by HTML and CSS
(although the HTML and CSS will be moved in a subsequent commit
to their own file).
4. Closing the file, rather than opening it, is the section on
Dangerous constructs. Some of these are fairly specialized, so
it makes sense not to ask readers to read through them before
presenting, say, our philosophy on line length.
Finally, in trying to come up with a sensible order for all sections
of this document, the "More arbitrary style things" heading has been
removed.
2023-05-22 22:06:13 +02:00
|
|
|
```
|
|
|
|
|
2023-05-23 17:37:51 +02:00
|
|
|
### Attach behaviors to event listeners
|
docs: Reorganize code style and conventions doc.
This commit represents an in-place reordering of the document. No
headings or content has been changed (that will happen in subsequent
commits).
The goal is to open the document with generic advice and guidance
applicable to all Zulip developers across all languages:
1. Consistency, enforced by linters and automated tests, opens the
document.
2. General, largely language-neutral advice about line length,
third-party code, translation, paths, and secrets come next.
3. Next up is language-specific advice and conventions: Python,
followed by JavaScript and TypeScript, followed by HTML and CSS
(although the HTML and CSS will be moved in a subsequent commit
to their own file).
4. Closing the file, rather than opening it, is the section on
Dangerous constructs. Some of these are fairly specialized, so
it makes sense not to ask readers to read through them before
presenting, say, our philosophy on line length.
Finally, in trying to come up with a sensible order for all sections
of this document, the "More arbitrary style things" heading has been
removed.
2023-05-22 22:06:13 +02:00
|
|
|
|
2023-05-23 17:37:51 +02:00
|
|
|
Attach callback functions to events using jQuery code. For example:
|
docs: Reorganize code style and conventions doc.
This commit represents an in-place reordering of the document. No
headings or content has been changed (that will happen in subsequent
commits).
The goal is to open the document with generic advice and guidance
applicable to all Zulip developers across all languages:
1. Consistency, enforced by linters and automated tests, opens the
document.
2. General, largely language-neutral advice about line length,
third-party code, translation, paths, and secrets come next.
3. Next up is language-specific advice and conventions: Python,
followed by JavaScript and TypeScript, followed by HTML and CSS
(although the HTML and CSS will be moved in a subsequent commit
to their own file).
4. Closing the file, rather than opening it, is the section on
Dangerous constructs. Some of these are fairly specialized, so
it makes sense not to ask readers to read through them before
presenting, say, our philosophy on line length.
Finally, in trying to come up with a sensible order for all sections
of this document, the "More arbitrary style things" heading has been
removed.
2023-05-22 22:06:13 +02:00
|
|
|
|
|
|
|
```js
|
2023-05-23 17:37:51 +02:00
|
|
|
$("body").on("click", ".move_message_button", function (e) {
|
|
|
|
// message-moving UI logic
|
|
|
|
}
|
docs: Reorganize code style and conventions doc.
This commit represents an in-place reordering of the document. No
headings or content has been changed (that will happen in subsequent
commits).
The goal is to open the document with generic advice and guidance
applicable to all Zulip developers across all languages:
1. Consistency, enforced by linters and automated tests, opens the
document.
2. General, largely language-neutral advice about line length,
third-party code, translation, paths, and secrets come next.
3. Next up is language-specific advice and conventions: Python,
followed by JavaScript and TypeScript, followed by HTML and CSS
(although the HTML and CSS will be moved in a subsequent commit
to their own file).
4. Closing the file, rather than opening it, is the section on
Dangerous constructs. Some of these are fairly specialized, so
it makes sense not to ask readers to read through them before
presenting, say, our philosophy on line length.
Finally, in trying to come up with a sensible order for all sections
of this document, the "More arbitrary style things" heading has been
removed.
2023-05-22 22:06:13 +02:00
|
|
|
```
|
|
|
|
|
2023-05-23 17:37:51 +02:00
|
|
|
That approach has multiple benefits:
|
docs: Reorganize code style and conventions doc.
This commit represents an in-place reordering of the document. No
headings or content has been changed (that will happen in subsequent
commits).
The goal is to open the document with generic advice and guidance
applicable to all Zulip developers across all languages:
1. Consistency, enforced by linters and automated tests, opens the
document.
2. General, largely language-neutral advice about line length,
third-party code, translation, paths, and secrets come next.
3. Next up is language-specific advice and conventions: Python,
followed by JavaScript and TypeScript, followed by HTML and CSS
(although the HTML and CSS will be moved in a subsequent commit
to their own file).
4. Closing the file, rather than opening it, is the section on
Dangerous constructs. Some of these are fairly specialized, so
it makes sense not to ask readers to read through them before
presenting, say, our philosophy on line length.
Finally, in trying to come up with a sensible order for all sections
of this document, the "More arbitrary style things" heading has been
removed.
2023-05-22 22:06:13 +02:00
|
|
|
|
|
|
|
- Potential huge performance gains by using delegated events where
|
|
|
|
possible
|
|
|
|
- When calling a function from an `onclick` attribute, `this` is not
|
|
|
|
bound to the element like you might think
|
|
|
|
- jQuery does event normalization
|
|
|
|
|
2023-05-23 17:37:51 +02:00
|
|
|
Do not use `onclick` attributes in the HTML.
|
docs: Reorganize code style and conventions doc.
This commit represents an in-place reordering of the document. No
headings or content has been changed (that will happen in subsequent
commits).
The goal is to open the document with generic advice and guidance
applicable to all Zulip developers across all languages:
1. Consistency, enforced by linters and automated tests, opens the
document.
2. General, largely language-neutral advice about line length,
third-party code, translation, paths, and secrets come next.
3. Next up is language-specific advice and conventions: Python,
followed by JavaScript and TypeScript, followed by HTML and CSS
(although the HTML and CSS will be moved in a subsequent commit
to their own file).
4. Closing the file, rather than opening it, is the section on
Dangerous constructs. Some of these are fairly specialized, so
it makes sense not to ask readers to read through them before
presenting, say, our philosophy on line length.
Finally, in trying to come up with a sensible order for all sections
of this document, the "More arbitrary style things" heading has been
removed.
2023-05-22 22:06:13 +02:00
|
|
|
|
2023-05-22 22:22:19 +02:00
|
|
|
### Declare variables using `const` and `let`
|
docs: Reorganize code style and conventions doc.
This commit represents an in-place reordering of the document. No
headings or content has been changed (that will happen in subsequent
commits).
The goal is to open the document with generic advice and guidance
applicable to all Zulip developers across all languages:
1. Consistency, enforced by linters and automated tests, opens the
document.
2. General, largely language-neutral advice about line length,
third-party code, translation, paths, and secrets come next.
3. Next up is language-specific advice and conventions: Python,
followed by JavaScript and TypeScript, followed by HTML and CSS
(although the HTML and CSS will be moved in a subsequent commit
to their own file).
4. Closing the file, rather than opening it, is the section on
Dangerous constructs. Some of these are fairly specialized, so
it makes sense not to ask readers to read through them before
presenting, say, our philosophy on line length.
Finally, in trying to come up with a sensible order for all sections
of this document, the "More arbitrary style things" heading has been
removed.
2023-05-22 22:06:13 +02:00
|
|
|
|
|
|
|
Always declare JavaScript variables using `const` or `let` rather than
|
|
|
|
`var`.
|
|
|
|
|
2023-05-22 22:22:19 +02:00
|
|
|
### Manipulate objects and arrays with modern methods
|
docs: Reorganize code style and conventions doc.
This commit represents an in-place reordering of the document. No
headings or content has been changed (that will happen in subsequent
commits).
The goal is to open the document with generic advice and guidance
applicable to all Zulip developers across all languages:
1. Consistency, enforced by linters and automated tests, opens the
document.
2. General, largely language-neutral advice about line length,
third-party code, translation, paths, and secrets come next.
3. Next up is language-specific advice and conventions: Python,
followed by JavaScript and TypeScript, followed by HTML and CSS
(although the HTML and CSS will be moved in a subsequent commit
to their own file).
4. Closing the file, rather than opening it, is the section on
Dangerous constructs. Some of these are fairly specialized, so
it makes sense not to ask readers to read through them before
presenting, say, our philosophy on line length.
Finally, in trying to come up with a sensible order for all sections
of this document, the "More arbitrary style things" heading has been
removed.
2023-05-22 22:06:13 +02:00
|
|
|
|
|
|
|
For functions that operate on arrays or JavaScript objects, you should
|
|
|
|
generally use modern
|
|
|
|
[ECMAScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Language_Resources)
|
|
|
|
primitives such as [`for … of`
|
|
|
|
loops](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of),
|
|
|
|
[`Array.prototype.{entries, every, filter, find, indexOf, map, some}`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array),
|
|
|
|
[`Object.{assign, entries, keys, values}`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object),
|
|
|
|
[spread
|
|
|
|
syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax),
|
|
|
|
and so on. Our Babel configuration automatically transpiles and
|
|
|
|
polyfills these using [`core-js`](https://github.com/zloirock/core-js)
|
|
|
|
when necessary. We used to use the
|
|
|
|
[Underscore](https://underscorejs.org/) library, but that should be
|
|
|
|
avoided in new code.
|
|
|
|
|
2023-05-22 22:22:19 +02:00
|
|
|
## HTML and CSS
|
docs: Reorganize code style and conventions doc.
This commit represents an in-place reordering of the document. No
headings or content has been changed (that will happen in subsequent
commits).
The goal is to open the document with generic advice and guidance
applicable to all Zulip developers across all languages:
1. Consistency, enforced by linters and automated tests, opens the
document.
2. General, largely language-neutral advice about line length,
third-party code, translation, paths, and secrets come next.
3. Next up is language-specific advice and conventions: Python,
followed by JavaScript and TypeScript, followed by HTML and CSS
(although the HTML and CSS will be moved in a subsequent commit
to their own file).
4. Closing the file, rather than opening it, is the section on
Dangerous constructs. Some of these are fairly specialized, so
it makes sense not to ask readers to read through them before
presenting, say, our philosophy on line length.
Finally, in trying to come up with a sensible order for all sections
of this document, the "More arbitrary style things" heading has been
removed.
2023-05-22 22:06:13 +02:00
|
|
|
|
2023-05-19 22:23:29 +02:00
|
|
|
See the documentation on [HTML and CSS](../subsystems/html-css.md)
|
|
|
|
for guidance on conventions in those language.
|
docs: Reorganize code style and conventions doc.
This commit represents an in-place reordering of the document. No
headings or content has been changed (that will happen in subsequent
commits).
The goal is to open the document with generic advice and guidance
applicable to all Zulip developers across all languages:
1. Consistency, enforced by linters and automated tests, opens the
document.
2. General, largely language-neutral advice about line length,
third-party code, translation, paths, and secrets come next.
3. Next up is language-specific advice and conventions: Python,
followed by JavaScript and TypeScript, followed by HTML and CSS
(although the HTML and CSS will be moved in a subsequent commit
to their own file).
4. Closing the file, rather than opening it, is the section on
Dangerous constructs. Some of these are fairly specialized, so
it makes sense not to ask readers to read through them before
presenting, say, our philosophy on line length.
Finally, in trying to come up with a sensible order for all sections
of this document, the "More arbitrary style things" heading has been
removed.
2023-05-22 22:06:13 +02:00
|
|
|
|
2023-05-22 22:22:19 +02:00
|
|
|
## Dangerous constructs in Django
|
2016-05-15 18:28:38 +02:00
|
|
|
|
2023-05-22 22:22:19 +02:00
|
|
|
### Avoid excessive database queries
|
2016-05-15 18:28:38 +02:00
|
|
|
|
|
|
|
Look out for Django code like this:
|
|
|
|
|
2021-08-20 07:09:04 +02:00
|
|
|
```python
|
|
|
|
bars = Bar.objects.filter(...)
|
|
|
|
for bar in bars:
|
|
|
|
foo = bar.foo
|
|
|
|
# Make use of foo
|
|
|
|
```
|
2016-05-15 18:28:38 +02:00
|
|
|
|
2020-05-18 23:01:41 +02:00
|
|
|
...because it equates to:
|
|
|
|
|
2021-08-20 07:09:04 +02:00
|
|
|
```python
|
|
|
|
bars = Bar.objects.filter(...)
|
|
|
|
for bar in bars:
|
|
|
|
foo = Foo.objects.get(id=bar.foo.id)
|
|
|
|
# Make use of foo
|
|
|
|
```
|
2020-05-18 23:01:41 +02:00
|
|
|
|
2023-05-23 17:48:54 +02:00
|
|
|
...which makes a database query for every `Bar`. While this may be fast
|
2021-08-20 21:53:28 +02:00
|
|
|
locally in development, it may be quite slow in production! Instead,
|
2020-05-18 23:01:41 +02:00
|
|
|
tell Django's [QuerySet
|
|
|
|
API](https://docs.djangoproject.com/en/dev/ref/models/querysets/) to
|
|
|
|
_prefetch_ the data in the initial query:
|
|
|
|
|
2021-08-20 07:09:04 +02:00
|
|
|
```python
|
|
|
|
bars = Bar.objects.filter(...).select_related()
|
|
|
|
for bar in bars:
|
|
|
|
foo = bar.foo # This doesn't take another query, now!
|
|
|
|
# Make use of foo
|
|
|
|
```
|
2016-05-15 18:28:38 +02:00
|
|
|
|
|
|
|
If you can't rewrite it as a single query, that's a sign that something
|
|
|
|
is wrong with the database schema. So don't defer this optimization when
|
|
|
|
performing schema changes, or else you may later find that it's
|
|
|
|
impossible.
|
|
|
|
|
2023-05-22 22:22:19 +02:00
|
|
|
### Never do direct database queries (`UserProfile.objects.get()`, `Client.objects.get()`, etc.)
|
2016-05-15 18:28:38 +02:00
|
|
|
|
|
|
|
In our Django code, never do direct `UserProfile.objects.get(email=foo)`
|
|
|
|
database queries. Instead always use `get_user_profile_by_{email,id}`.
|
|
|
|
There are 3 reasons for this:
|
|
|
|
|
|
|
|
1. It's guaranteed to correctly do a case-inexact lookup
|
|
|
|
2. It fetches the user object from remote cache, which is faster
|
2020-05-18 23:01:41 +02:00
|
|
|
3. It always fetches a UserProfile object which has been queried
|
2023-05-23 17:48:54 +02:00
|
|
|
using `.select_related()` ([see above](#avoid-excessive-database-queries)!),
|
|
|
|
and thus will perform well when one later accesses related models
|
|
|
|
like the Realm.
|
2016-05-15 18:28:38 +02:00
|
|
|
|
2020-05-18 23:05:52 +02:00
|
|
|
Similarly we have `get_client` and `access_stream_by_id` /
|
|
|
|
`access_stream_by_name` functions to fetch those commonly accessed
|
|
|
|
objects via remote cache.
|
2016-05-15 18:28:38 +02:00
|
|
|
|
2023-05-22 22:22:19 +02:00
|
|
|
### Don't use Django model objects as keys in sets/dicts
|
2016-05-15 18:28:38 +02:00
|
|
|
|
|
|
|
Don't use Django model objects as keys in sets/dictionaries -- you will
|
|
|
|
get unexpected behavior when dealing with objects obtained from
|
|
|
|
different database queries:
|
|
|
|
|
2020-05-18 23:15:27 +02:00
|
|
|
For example, the following will, surprisingly, fail:
|
|
|
|
|
2021-08-20 07:09:04 +02:00
|
|
|
```python
|
2020-05-18 23:15:27 +02:00
|
|
|
# Bad example -- will raise!
|
|
|
|
obj: UserProfile = get_user_profile_by_id(17)
|
|
|
|
some_objs = UserProfile.objects.get(id=17)
|
|
|
|
assert obj in set([some_objs])
|
|
|
|
```
|
|
|
|
|
|
|
|
You should work with the IDs instead:
|
|
|
|
|
2021-08-20 07:09:04 +02:00
|
|
|
```python
|
2020-05-18 23:15:27 +02:00
|
|
|
obj: UserProfile = get_user_profile_by_id(17)
|
|
|
|
some_objs = UserProfile.objects.get(id=17)
|
2022-12-27 19:43:52 +01:00
|
|
|
assert obj.id in set([o.id for o in some_objs])
|
2020-05-18 23:15:27 +02:00
|
|
|
```
|
2016-05-15 18:28:38 +02:00
|
|
|
|
2023-05-22 22:22:19 +02:00
|
|
|
### Don't call user_profile.save() without `update_fields`
|
2016-05-15 18:28:38 +02:00
|
|
|
|
2023-05-23 17:48:54 +02:00
|
|
|
You should always pass the `update_fields` keyword argument to `.save()`
|
|
|
|
when modifying an existing Django model object. By default, `.save()` will
|
2016-05-15 18:28:38 +02:00
|
|
|
overwrite every value in the column, which results in lots of race
|
|
|
|
conditions where unrelated changes made by one thread can be
|
2023-05-23 17:48:54 +02:00
|
|
|
accidentally overwritten by another thread that fetched its `UserProfile`
|
2016-05-15 18:28:38 +02:00
|
|
|
object before the first thread wrote out its change.
|
|
|
|
|
2023-05-22 22:22:19 +02:00
|
|
|
### Don't update important model objects with raw saves
|
2016-05-15 18:28:38 +02:00
|
|
|
|
2022-04-14 00:48:36 +02:00
|
|
|
In most cases, we already have a function in `zerver.actions` with
|
2023-05-23 17:48:54 +02:00
|
|
|
a name like `do_activate_user` that will correctly handle lookups,
|
2016-05-15 18:28:38 +02:00
|
|
|
caching, and notifying running browsers via the event system about your
|
|
|
|
change. So please check whether such a function exists before writing
|
|
|
|
new code to modify a model object, since your new code has a good chance
|
|
|
|
of getting at least one of these things wrong.
|
|
|
|
|
2023-05-22 22:22:19 +02:00
|
|
|
### Don't use naive datetime objects
|
2017-02-28 00:37:33 +01:00
|
|
|
|
2022-02-24 21:15:43 +01:00
|
|
|
Python allows datetime objects to not have an associated time zone, which can
|
2017-02-28 00:37:33 +01:00
|
|
|
cause time-related bugs that are hard to catch with a test suite, or bugs
|
2023-05-23 17:48:54 +02:00
|
|
|
that only show up during daylight saving time.
|
2017-02-28 00:37:33 +01:00
|
|
|
|
2022-02-24 21:15:43 +01:00
|
|
|
Good ways to make time-zone-aware datetimes are below. We import time zone
|
2021-09-08 00:23:24 +02:00
|
|
|
libraries as `from datetime import datetime, timezone` and
|
|
|
|
`from django.utils.timezone import now as timezone_now`.
|
2020-05-18 23:16:34 +02:00
|
|
|
|
|
|
|
Use:
|
2021-08-20 22:54:08 +02:00
|
|
|
|
2021-08-20 21:45:39 +02:00
|
|
|
- `timezone_now()` to get a datetime when Django is available, such as
|
2020-05-18 23:16:34 +02:00
|
|
|
in `zerver/`.
|
2021-08-20 21:45:39 +02:00
|
|
|
- `datetime.now(tz=timezone.utc)` when Django is not available, such as
|
2020-05-18 23:16:34 +02:00
|
|
|
for bots and scripts.
|
2021-08-20 21:45:39 +02:00
|
|
|
- `datetime.fromtimestamp(timestamp, tz=timezone.utc)` if creating a
|
2017-02-28 00:37:33 +01:00
|
|
|
datetime from a timestamp. This is also available as
|
|
|
|
`zerver.lib.timestamp.timestamp_to_datetime`.
|
2021-08-20 21:45:39 +02:00
|
|
|
- `datetime.strptime(date_string, format).replace(tzinfo=timezone.utc)` if
|
2017-02-28 00:37:33 +01:00
|
|
|
creating a datetime from a formatted string that is in UTC.
|
|
|
|
|
2022-02-24 21:15:43 +01:00
|
|
|
Idioms that result in time-zone-naive datetimes, and should be avoided, are
|
2017-02-28 00:37:33 +01:00
|
|
|
`datetime.now()` and `datetime.fromtimestamp(timestamp)` without a `tz`
|
|
|
|
parameter, `datetime.utcnow()` and `datetime.utcfromtimestamp()`, and
|
|
|
|
`datetime.strptime(date_string, format)` without replacing the `tzinfo` at
|
|
|
|
the end.
|
|
|
|
|
|
|
|
Additional notes:
|
2021-08-20 22:54:08 +02:00
|
|
|
|
2021-08-20 21:45:39 +02:00
|
|
|
- Especially in scripts and puppet configuration where Django is not
|
2017-02-28 00:37:33 +01:00
|
|
|
available, using `time.time()` to get timestamps can be cleaner than
|
|
|
|
dealing with datetimes.
|
2021-08-20 21:45:39 +02:00
|
|
|
- All datetimes on the backend should be in UTC, unless there is a good
|
2017-02-28 00:37:33 +01:00
|
|
|
reason to do otherwise.
|
|
|
|
|
2023-05-22 22:22:19 +02:00
|
|
|
## Dangerous constructs in JavaScript and TypeScript
|
|
|
|
|
|
|
|
### Do not use `for...in` statements to traverse arrays
|
2016-05-15 18:28:38 +02:00
|
|
|
|
2023-05-22 22:22:19 +02:00
|
|
|
That construct pulls in properties inherited from the prototype chain.
|
2016-05-15 18:28:38 +02:00
|
|
|
Don't use it:
|
2020-03-27 01:32:21 +01:00
|
|
|
[[1]](https://stackoverflow.com/questions/500504/javascript-for-in-with-arrays),
|
2016-10-24 20:06:43 +02:00
|
|
|
[[2]](https://google.github.io/styleguide/javascriptguide.xml#for-in_loop),
|
2020-03-27 01:32:21 +01:00
|
|
|
[[3]](https://www.jslint.com/help.html#forin)
|