diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-02-10 03:09:33 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-02-10 03:09:33 +0300 |
commit | 5a120c32fda1c88e38bbce056d6f30f4a2f41bc6 (patch) | |
tree | 8f5ef3c06e5f2f8707da5d32803d73fe10824ea5 /doc/development | |
parent | b5944525b015e4efb4cd2c1d09ec37566d7691a0 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'doc/development')
-rw-r--r-- | doc/development/README.md | 1 | ||||
-rw-r--r-- | doc/development/documentation/index.md | 83 | ||||
-rw-r--r-- | doc/development/transient/prevention-patterns.md | 132 |
3 files changed, 166 insertions, 50 deletions
diff --git a/doc/development/README.md b/doc/development/README.md index d73acdd9dbc..5db4c5438c4 100644 --- a/doc/development/README.md +++ b/doc/development/README.md @@ -294,6 +294,7 @@ See [database guidelines](database/index.md). - [Compatibility with multiple versions of the application running at the same time](multi_version_compatibility.md) - [Features inside `.gitlab/`](features_inside_dot_gitlab.md) - [Dashboards for stage groups](stage_group_dashboards.md) +- [Preventing transient bugs](transient/prevention-patterns.md) ## Other GitLab Development Kit (GDK) guides diff --git a/doc/development/documentation/index.md b/doc/development/documentation/index.md index b878f0fc1ce..6b30a6dab5d 100644 --- a/doc/development/documentation/index.md +++ b/doc/development/documentation/index.md @@ -328,68 +328,51 @@ with GitLab 11.4. Meaning, it's available only with `/help` from GitLab ### Linking to `/help` -When you're building a new feature, you may need to link the documentation -from GitLab, the application. This is normally done in files inside the -`app/views/` directory with the help of the `help_page_path` helper method. +When you're building a new feature, you may need to link to the documentation +from the GitLab application. This is normally done in files inside the +`app/views/` directory, with the help of the `help_page_path` helper method. -In its simplest form, the HAML code to generate a link to the `/help` page is: +The `help_page_path` contains the path to the document you want to link to, +with the following conventions: -```haml -= link_to 'Help page', help_page_path('user/permissions') -``` - -The `help_page_path` contains the path to the document you want to link to with -the following conventions: - -- it is relative to the `doc/` directory in the GitLab repository -- the `.md` extension must be omitted -- it must not end with a slash (`/`) - -Below are some special cases where should be used depending on the context. -You can combine one or more of the following: - -1. **Linking to an anchor link.** Use `anchor` as part of the `help_page_path` - method: +- It's relative to the `doc/` directory in the GitLab repository. +- It omits the `.md` extension. +- It doesn't end with a slash (`/`). - ```haml - = link_to 'Help page', help_page_path('user/permissions', anchor: 'anchor-link') - ``` +The help text follows the [Pajamas guidelines](https://design.gitlab.com/usability/helping-users/#formatting-help-content). -1. **Opening links in a new tab.** This should be the default behavior: +Use the following special cases depending on the context, ensuring all links +are inside `_()` so they can be translated: - ```haml - = link_to 'Help page', help_page_path('user/permissions'), target: '_blank' - ``` +- Linking to a doc page. In its most basic form, the HAML code to generate a + link to the `/help` page is: -1. **Using a question icon.** Usually used in settings where a long - description cannot be used, like near checkboxes. You can basically use - any GitLab SVG icon, but prefer the `question-o`: - - ```haml - = link_to sprite_icon('question-o'), help_page_path('user/permissions') - ``` + ```haml + = link_to _('Learn more.'), help_page_path('user/permissions'), target: '_blank', rel: 'noopener noreferrer' + ``` -1. **Using a button link.** Useful in places where text would be out of context - with the rest of the page layout: +- Linking to an anchor link. Use `anchor` as part of the `help_page_path` + method: - ```haml - = link_to 'Help page', help_page_path('user/permissions'), class: 'btn btn-info' - ``` + ```haml + = link_to _('Learn more.'), help_page_path('user/permissions', anchor: 'anchor-link'), target: '_blank', rel: 'noopener noreferrer' + ``` -1. **Using links inline of some text.** +- Using links inline of some text. First, define the link, and then use it. In + this example, `link_start` is the name of the variable that contains the + link: - ```haml - Description to #{link_to 'Help page', help_page_path('user/permissions')}. - ``` + ```haml + - link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/permissions') } + %p= _("This is a text describing the option/feature in a sentence. %{link_start}Learn more.%{link_end}").html_safe % { link_start: link_start, link_end: '</a>'.html_safe } + ``` -1. **Adding a period at the end of the sentence.** Useful when you don't want - the period to be part of the link: +- Using a button link. Useful in places where text would be out of context with + the rest of the page layout: - ```haml - = succeed '.' do - Learn more in the - = link_to 'Help page', help_page_path('user/permissions') - ``` + ```haml + = link_to _('Learn more.'), help_page_path('user/permissions'), class: 'btn btn-info', target: '_blank', rel: 'noopener noreferrer' + ``` #### Linking to `/help` in JavaScript diff --git a/doc/development/transient/prevention-patterns.md b/doc/development/transient/prevention-patterns.md new file mode 100644 index 00000000000..7231562415b --- /dev/null +++ b/doc/development/transient/prevention-patterns.md @@ -0,0 +1,132 @@ +--- +stage: none +group: unassigned +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments +--- + +# Preventing Transient Bugs + +This page will cover architectural patterns and tips for developers to follow to prevent [transient bugs.](https://about.gitlab.com/handbook/engineering/quality/issue-triage/#transient-bugs) + +## Frontend + +### Don't rely on response order + +When working with multiple requests, it's easy to assume the order of the responses will match the order in which they are triggered. + +That's not always the case and can cause bugs that only happen if the order is switched. + +**Example:** + +- `diffs_metadata.json` (lighter) +- `diffs_batch.json` (heavier) + +If your feature requires data from both, ensure that the two have finished loading before working on it. + +### Simulate slower connections when testing manually + +Add a network condition template to your browser's dev tools to enable you to toggle between a slow and a fast connection. + +**Example:** + +- Turtle: + - Down: 50kb/s + - Up: 20kb/s + - Latency: 10000ms + +### Collapsed elements + +When setting event listeners, if not possible to use event delegation, ensure all relevant event listeners are set for expanded content. + +Including when that expanded content is: + +- **Invisible** (`display: none;`). Some JavaScript requires the element to be visible to work properly (eg.: when taking measurements). +- **Dynamic content** (AJAX/DOM manipulation). + +### Using assertions to detect transient bugs caused by unmet conditions + +Transient bugs happen in the context of code that executes under the assumption +that the application’s state meets one or more conditions. We may write a feature +that assumes a server-side API response always include a group of attributes or that +an operation only executes when the application has successfully transitioned to a new +state. + +Transient bugs are difficult to debug because there isn’t any mechanism that alerts +the user or the developer about unsatisfied conditions. These conditions are usually +not expressed explicitly in the code. A useful debugging technique for such situations +is placing assertions to make any assumption explicit. They can help detect the cause +which unmet condition causes the bug. + +#### Asserting pre-conditions on state mutations + +A common scenario that leads to transient bugs is when there is a polling service +that should mutate state only if a user operation is completed. We can use +assertions to make this pre-condition explicit: + +```javascript +// This action is called by a polling service. It assumes that all pre-conditions +// are satisfied by the time the action is dispatched. +export const updateMergeableStatus = ({ commit }, payload) => { + commit(types.SET_MERGEABLE_STATUS, payload); +}; + +// We can make any pre-condition explicit by adding an assertion +export const updateMergeableStatus = ({ state, commit }, payload) => { + console.assert( + state.isResolvingDiscussion === true, + 'Resolve discussion request must be completed before updating mergeable status' + ); + commit(types.SET_MERGEABLE_STATUS, payload); +}; +``` + +#### Asserting API contracts + +Another useful way of using assertions is to detect if the response payload returned +by the server-side endpoint satisfies the API contract. + +#### Related reading + +[Debug it!](https://pragprog.com/titles/pbdp/debug-it/) explores techniques to diagnose +and fix non-determinstic bugs and write software that is easier to debug. + +## Backend + +### Sidekiq jobs with locks + +When dealing with asynchronous work via Sidekiq, it is possible to have 2 jobs with the same arguments +getting worked on at the same time. If not handled correctly, this can result in an outdated or inaccurate state. + +For instance, consider a worker that updates a state of an object. Before the worker updates the state +(for example, `#update_state`) of the object, it needs to check what the appropriate state should be +(for example, `#check_state`). + +When there are 2 jobs being worked on at the same time, it is possible that the order of operations will go like: + +1. (Worker A) Calls `#check_state` +1. (Worker B) Calls `#check_state` +1. (Worker B) Calls `#update_state` +1. (Worker A) Calls `#update_state` + +In this example, `Worker B` is meant to set the updated status. But `Worker A` calls `#update_state` a little too late. + +This can be avoided by utilizing either database locks or `Gitlab::ExclusiveLease`. This way, jobs will be +worked on one at a time. This also allows them to be marked as [idempotent](../sidekiq_style_guide.md#idempotent-jobs). + +### Retry mechanism handling + +There are times that an object/record will be on a failed state which can be rechecked. + +If an object is in a state that can be rechecked, ensure that appropriate messaging is shown to the user +so they know what to do. Also, make sure that the retry functionality will be able to reset the state +correctly when triggered. + +### Error Logging + +Error logging doesn't necessarily directly prevents transient bugs but it can help to debug them. + +When coding, sometimes we expect some exceptions to be raised and we rescue them. + +Logging whenever we rescue an error helps in case it's causing transient bugs that a user may see. +While investigating a bug report, it may require the engineer to look into logs of when it happened. +Seeing an error being logged can be a signal of something that went wrong which can be handled differently. |