├── style ├── react.md ├── java.md ├── graphql.md ├── css.md ├── javascript.md ├── ios.md ├── python.md ├── android-development-best-practices.md └── go.md ├── Readme.md ├── gh-md-toc └── configs └── KhanAcademyAndroid.xml /style/react.md: -------------------------------------------------------------------------------- 1 | # React style guide 2 | 3 | ---- 4 | 5 | > Follow the normal [JavaScript style guide](javascript.md). We generally try to follow the official [React tutorials and guides](https://react.dev/reference/react). Please default to them as a source-of-truth. 6 | 7 | ---- 8 | 9 | ## Syntax 10 | 11 | ### Prefer to export a single React component 12 | 13 | Every .tsx file should ideally export a single React component. 14 | This is for testability and composition; it's easier to write Storybook stories and 15 | it's clearer where the breaks in functionality are. 16 | 17 | Note that the file can still define multiple components, it just shouldn't export 18 | more than one. 19 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Khan Academy Coding Style Guides 2 | 3 | We implement a style guide for our code with the intention of keeping things readable and consistent. Please do your part on the team to help keep the spirit of this consistency in both your own code, as well as politely pointing out violations in other people's code when doing their code reviews. While code prettiness should never be valued over launching or any user-visible impacting changes to the code, the idea is that maintaining a readable codebase helps things be more maintainable, and in the long run will make it easier to do the real changes that do make user-visible changes. 4 | 5 | There may be lots of legacy files that do not adhere to the current style guide; if you're editing an old file, be consistent with what's around you. 6 | 7 | To help adhere to these rules, some tools are available to automatically catch, and in some cases fix, style violations. See the per-language guides below for more info. 8 | 9 | ## TODOs 10 | 11 | If there is something that you want to deal with later, it’s appropriate to mark it in code. There’s an advantage to using a standard format, which is this: 12 | 13 | ``` 14 | # TODO(your_username): Fix this to work with frobnozzes too 15 | # TODO(your_username): Remove this once we support quxxes (at least by Dec 2012) 16 | ``` 17 | 18 | The text TODO is followed by your username in parentheses. This does not mean that you are on the hook to follow through on the TODO. Rather, it means that you are the person most knowledgeable about it, so if others run across the TODO and have questions about it, they know who to talk to. 19 | 20 | In code reviews, it is common to put in TODOs when a reviewer points out some thing in the code that could be improved, but is not necessary to do right away. 21 | 22 | ## Language Style Guides 23 | 24 | - [JavaScript](/style/javascript.md) 25 | - [React](/style/react.md) 26 | - [CSS](/style/css.md) 27 | - [Python](/style/python.md) 28 | - [Go](/style/go.md) 29 | - [Java](/style/java.md) 30 | - [ObjC](https://github.com/Khan/objective-c-style-guide) (hosted separately) 31 | - [iOS](/style/ios.md) 32 | -------------------------------------------------------------------------------- /style/java.md: -------------------------------------------------------------------------------- 1 | # Java 2 | 3 | At Khan Academy, we only use Java for Android and, as such, follow the [Android Code Style Guidelines for Contributors](https://source.android.com/source/code-style.html). Note that those rules themselves extend the [standard Java language style guide as of 1999](http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-141855.html). The rest of this document describes additions and clarifications to those rules that we follow at Khan Academy. 4 | 5 | To import these settings for Android Studio, copy [the config file](/configs/KhanAcademyAndroid.xml) into `$HOME/Library/Preferences/AndroidStudio/codestyles/`. 6 | 7 | ## Imports 8 | 9 | Import statements are divided into the following groups, in this order, with each group separated by a blank line: 10 | 11 | 1. All static imports in a single group 12 | 2. org.khanacademy imports 13 | 3. All other non-Android third-party imports, in ASCII sort order (for example: com, junit, org, sun) 14 | 4. android imports 15 | 5. java imports 16 | 6. javax imports 17 | 18 | Imports are not subject to the 100 column limit rule; they should never be wrapped. 19 | 20 | We prefer using static imports when using the following: 21 | 22 | - `com.google.common.base.Preconditions.*` (e.g. `checkNotNull`) 23 | - `org.junit.Assert.*` (e.g. `assertEquals`) 24 | 25 | 26 | ## No per-file boilerplate 27 | 28 | We do not include copyright or `@author` or `Created by` boilerplate at the top of files. The first line of the file is typically the `package` statement. 29 | 30 | Package statements are not subject to the 100 column limit rule; they should never be wrapped. 31 | 32 | 33 | ## Use your best judgement for Javadoc 34 | 35 | We don't strictly require Javadoc for _all_ public methods, though it's _strongly_ encouraged for non-trivial ones. 36 | 37 | 38 | ## Use `@Override` where possible 39 | 40 | In addition to requiring the `@Override` tag when a class overrides the declration or implementation from a superclass, we also require it to be used when classes implement a method from an implemented interface. 41 | 42 | 43 | ## No single-line if statements. 44 | 45 | Bad: 46 | ```java 47 | 48 | if (foo) {bar();} // No single-line if statements 49 | 50 | // ...and braces are always required 51 | if (foo) 52 | bar(); 53 | ``` 54 | 55 | Good: 56 | ```java 57 | if (foo) { 58 | bar(); 59 | } 60 | ``` 61 | 62 | 63 | ## No C-style array declarations 64 | 65 | The square brackets form part of the _type_, not the variable. 66 | 67 | Good: `String[] args` 68 | Bad: `String args[]` 69 | 70 | 71 | ## Use TODO comments with author name 72 | 73 | Extending [AOSP style guide](https://source.android.com/setup/code-style#use-todo-comments), TODOs should include the string TODO in all caps, the author's name in parentheses, and a colon: 74 | 75 | `// TODO(author): ...` 76 | 77 | 78 | ## Use `final` variables when possible 79 | 80 | Mark variables that should only be initialized once as `final`. This includes function arguments. 81 | 82 | -------------------------------------------------------------------------------- /style/graphql.md: -------------------------------------------------------------------------------- 1 | # Graphql 2 | 3 | ## Docstrings 4 | 5 | When writing a schema definition file (`graphql.schema`), every type 6 | and field should be documented. The schema file is the main source of 7 | documentation for users who are crafting graphql queries and need to 8 | know what fields to ask for. We use triple-quotes for documentation, 9 | since they are automatically picked up by GraphiQL and other graphql 10 | UIs. 11 | 12 | ### Example 13 | 14 | ```graphql 15 | """ 16 | Summary of what this type is for; must fit on one line. 17 | 18 | After the blank line, you can spend as much space talking 19 | about this type as you'd like. 20 | """ 21 | interface Book { 22 | """Summary of this field; must fit on one line. 23 | If you need more space for discussing this field, 24 | you can use more lines, but don't use a blank line 25 | here. If applicable, give examples of valid values. 26 | Examples: Sal Khan, Artemis Fowl 27 | """ 28 | author: String! 29 | 30 | # Normal (`#`-prefixed) comments are not exposed via GraphiQL. 31 | # They are appropriate for text that is useful for code-authors but 32 | # not code-users. 33 | """This field needs only one line to describe it.""" 34 | publishYear: Number 35 | 36 | # We don't need a docstring here; the documentation is inside @deprecated. 37 | published: Boolean @deprecated( 38 | reason: "Use publishYear instead.") 39 | 40 | """The company that published the book. 41 | Valid values: Random House, Macmillan, University of California Press 42 | """" 43 | publisher: String 44 | } 45 | 46 | type Hardcover implements Book { 47 | # These fields are defined on the Book interface. 48 | author: String! 49 | publishYear: Number 50 | published: Boolean 51 | 52 | """The number of pages the hardcover version of this book has.""" 53 | numPages: Number! 54 | } 55 | ``` 56 | 57 | ### Commenting types 58 | 59 | Top level datatypes -- `Type`, `Interface`, `Union`, etc -- have a 60 | line of `"""` by itself, followed by a one-line summary of the 61 | datatype, followed by a blank line, followed by other text describing 62 | the type, ending with a `"""` on its own line. 63 | 64 | This comment style helps point out, visually, where one type ends and 65 | a new type begins. 66 | 67 | ### Commenting fields 68 | 69 | Almost all fields within a `Type` should have a docstring. This 70 | docstring should start with a `"""` followed by a one-line summary of 71 | the field, all on one line. If more documentation is needed, text can 72 | follow on the next line. There should never be a blank line in a 73 | field-docstring. 74 | 75 | Unless it's entirely obvious, give an example of possible value or two 76 | via the line: `Example: ..., ....`. Do not put quotes around the 77 | examples unless it's needed for clarity. 78 | 79 | When appropriate -- especially when an object has type "String" but is 80 | semantically an enum -- include a line `Valid values: ..., ...` that 81 | lists all valid values that the field could have. 82 | 83 | If the docstring is one line long, the trailing `"""` should go on 84 | that one line. Otherwise, the trailing `"""` should go on a line of 85 | its own. 86 | 87 | There should always be a blank line between a field and the docstring 88 | that introduces the next field. 89 | 90 | Always use triple-quotes, never a single quote, even for one-line 91 | docstrings. 92 | 93 | This comment style makes it easy to find field definitions within a 94 | type. In particular, blank lines are *only* used to separate fields. 95 | There are never blank lines within the text pertaining to a field. 96 | 97 | ### Commenting deprecated fields 98 | 99 | If *new code* should not query on a particular field, mark that fact 100 | with a `@deprecated` tag. The `reason` associated with that tag 101 | should say what to use instead. A docstring is not needed for this 102 | field, since no new code should be using it. (It's not forbidden to 103 | have a docstring, though.) 104 | 105 | You can mark a field `@deprecated` even if existing graphql queries 106 | use it. The `@deprecated` tag is meant only as a signal for people 107 | writing *new* graphql queries, that they should not be using this 108 | field anymore. 109 | 110 | ### Commenting interfaces 111 | 112 | If you write an interface, you should document all the fields of that 113 | interface, just like any other type. 114 | 115 | When you define a type that implements that interface, you will need 116 | to copy the fields over again, but you do *not* need to copy the 117 | docstrings for those fields. 118 | 119 | In an ideal world, Graphiql and other graphql browsers would know to 120 | copy the docstrings from the interface to its various 121 | implementations. Right now they don't, but we'd rather fix them in 122 | code than make people copy documentation all over the place. 123 | -------------------------------------------------------------------------------- /style/css.md: -------------------------------------------------------------------------------- 1 | # CSS 2 | 3 | Welcome to the CSS style guide. This guide borrows heavily from Github's [Primer CSS guidelines](http://primercss.io/guidelines/), so thanks to them! 4 | 5 | ## Coding Style 6 | 7 | - Use a four space indent. 8 | - Put spaces after : in property declarations. 9 | - Spaces before braces: put spaces before { in rule declarations. 10 | - Do not use trailing commas when listing multiple selectors 11 | - Separate selector and property declarations with a new line 12 | - Separate rules with a new line 13 | - End properties declarations with a ; 14 | - Alphabetize properties within rule declarations 15 | - Properties with values of 0 should *not* have units 16 | - Use lowercase hex color codes #fff unless using rgba. 17 | - Use /* */ for block comments (instead of //). 18 | - Use a maximum line length of 80 characters (rationale: looking at files side-by-side) 19 | - Use dashes in selectors instead of underscores (.my-class, not .my_class) 20 | 21 | Here is good example syntax: 22 | 23 | ```css 24 | /* This is a good example! */ 25 | .styleguide-format, 26 | .other-format, 27 | .third-format { 28 | background: rgba(0,0,0,0.5); 29 | border: 1px solid #0f0; 30 | color: #000; 31 | margin: 0; 32 | } 33 | 34 | .next-rule { 35 | color: #000; 36 | } 37 | ``` 38 | 39 | ## CSS Specificity Guidelines 40 | 41 | Elements that occur **exactly once** inside a page should use IDs, otherwise, use classes. When in doubt, use a class name. 42 | 43 | - **Good** candidates for ids: header, footer, modal popups. 44 | - **Bad** candidates for ids: navigation, item listings, item view pages (ex: issue view). 45 | 46 | - If you must use an id selector (`#selector`) make sure that you have no more than one in your rule declaration. A rule like `#header .search #quicksearch { ... }` is considered harmful. Curious why? Check out this primer on [CSS specificity](http://css-tricks.com/specifics-on-css-specificity/). 47 | - Do not combine id selectors with tags (`div#container`). The id should be specific enough, and should not be repeated elsewhere to necessitate the tag name. Try to follow the same guidelines for classes as well. 48 | - When modifying an existing element for a specific use, try to use specific class names. Instead of `.listings-layout.bigger` use rules like `.listings-layout.listings-bigger`. Think about ack/greping your code in the future. 49 | - Key (rightmost) Selectors should be as specific as possible. For example `a.navigation-link` instead of `#navigation-links a`. This has [performance implications](http://www.stevesouders.com/blog/2009/06/18/simplifying-css-selectors/). 50 | 51 | ## Less Guidelines 52 | 53 | If you aren't familiar with Less, [check out the documentation](http://lesscss.org/). 54 | 55 | - Branding items such as colors and pixel measurements for font sizes should always be placed in a variable, either in `shared-package/variables.less` or local to your stylesheet where applicable. Look for a variable before defining your own. 56 | - Any `@variable` or `.mixin` that is used in more than one file should be put in the appropriate package or, if used across packages, in variables.less or mixins.less in shared-package. Others should be put at the top of the file where they're used. 57 | - Don't nest further than 4 levels deep. If you find yourself going further, think about reorganizing your rules (either the specificity needed, or the layout of the nesting). 58 | 59 | ```less 60 | /* 61 | * This is a good example of rule nesting with Less. 62 | */ 63 | .third-format { 64 | background: @transparentGray; 65 | border: 1px solid @green; 66 | color: @black; 67 | margin: 0; 68 | 69 | .next-rule { // outputs: .third-format .next-rule {...} 70 | color: @white; 71 | } 72 | 73 | &.next-rule { // outputs: .third-format.next-rule {...} 74 | color: @lightGray; 75 | } 76 | 77 | > .next-rule { // outputs: .third-format > .next-rule {...} 78 | color: @red; 79 | } 80 | } 81 | ``` 82 | 83 | - If you are creating mixins that don't take parameters in a file that is going to be imported elsewhere (e.g. `shared-package/mixins.less`), include an empty parameter list to guard against the class being output each time the file is imported. 84 | 85 | ```less 86 | .parameterless-mixin-in-an-imported-less-file() { 87 | /* The empty parameter list allows the mixin to be used without 88 | * params and prevents the Less compiler from spitting it out 89 | * each time the file is imported 90 | */ 91 | background: @transparentGray; 92 | } 93 | ``` 94 | 95 | ## Pixels vs. Ems 96 | 97 | Use `px` for `font-size`, because it offers absolute control over text. **You should almost never have to define a font-size for anything**. If you feel the need to do it, stop yourself and look through existing shared styles for an applicable class. 98 | 99 | ## File Structure 100 | 101 | If you are adding Less files to a package you are working on, add only a single Less file to the list in packages.py that imports all of the required files like this: 102 | 103 | ```scss 104 | @import "../shared-package/variables.less"; 105 | @import "../shared-package/mixins.less"; 106 | @import "my-new-package-file.less"; 107 | @import "my-second-package-file.less"; 108 | ``` 109 | 110 | With this approach, all imports are done in this file. This prevents duplications in the compiled CSS that are caused by cascading imports of the same file. 111 | -------------------------------------------------------------------------------- /gh-md-toc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # 4 | # Steps: 5 | # 6 | # 1. Download corresponding html file for some README.md: 7 | # curl -s $1 8 | # 9 | # 2. Discard rows where no substring 'user-content-' (github's markup): 10 | # awk '/user-content-/ { ... 11 | # 12 | # 3.1 Get last number in each row like ' ... sitemap.js'. 13 | # It's a level of the current header (NF — number of fields): 14 | # substr($NF, length($NF)-1, 1) 15 | # 16 | # 3.2 Get level from 3.1 and insert corresponding number of spaces before '*': 17 | # sprintf("%*s", substr($NF, length($NF)-1, 1)*2, " ") 18 | # 19 | # 4. Find head's text and insert it inside "* [ ... ]": 20 | # substr($0, match($0, /a>.*<\/h/)+2, RLENGTH-5) 21 | # 22 | # 5. Find anchor and insert it inside "(...)": 23 | # substr($0, match($0, "href=\".*\" ")+5, RLENGTH-6) 24 | # 25 | 26 | gh_toc_version="0.4.5" 27 | 28 | gh_user_agent="gh-md-toc v$gh_toc_version" 29 | 30 | # 31 | # Download rendered into html README.md by its url. 32 | # 33 | # 34 | gh_toc_load() { 35 | local gh_url=$1 36 | 37 | if type curl &>/dev/null; then 38 | curl --user-agent "$gh_user_agent" -s "$gh_url" 39 | elif type wget &>/dev/null; then 40 | wget --user-agent="$gh_user_agent" -qO- "$gh_url" 41 | else 42 | echo "Please, install 'curl' or 'wget' and try again." 43 | exit 1 44 | fi 45 | } 46 | 47 | # 48 | # Converts local md file into html by GitHub 49 | # 50 | # ➥ curl -X POST --data '{"text": "Hello world github/linguist#1 **cool**, and #1!"}' https://api.github.com/markdown 51 | #

Hello world github/linguist#1 cool, and #1!

'" 52 | gh_toc_md2html() { 53 | local gh_file_md=$1 54 | curl -s --user-agent "$gh_user_agent" \ 55 | --data-binary @$gh_file_md -H "Content-Type:text/plain" \ 56 | https://api.github.com/markdown/raw 57 | } 58 | 59 | # 60 | # Is passed string url 61 | # 62 | gh_is_url() { 63 | if [[ $1 == https* || $1 == http* ]]; then 64 | echo "yes" 65 | else 66 | echo "no" 67 | fi 68 | } 69 | 70 | # 71 | # TOC generator 72 | # 73 | gh_toc(){ 74 | local gh_src=$1 75 | local gh_src_copy=$1 76 | local gh_ttl_docs=$2 77 | 78 | if [ "$gh_src" = "" ]; then 79 | echo "Please, enter URL or local path for a README.md" 80 | exit 1 81 | fi 82 | 83 | 84 | # Show "TOC" string only if working with one document 85 | if [ "$gh_ttl_docs" = "1" ]; then 86 | 87 | echo "Table of Contents" 88 | echo "=================" 89 | echo "" 90 | gh_src_copy="" 91 | 92 | fi 93 | 94 | if [ "$(gh_is_url $gh_src)" == "yes" ]; then 95 | gh_toc_load "$gh_src" | gh_toc_grab "$gh_src_copy" 96 | else 97 | gh_toc_md2html "$gh_src" | gh_toc_grab "$gh_src_copy" 98 | fi 99 | } 100 | 101 | GH_GREP="grep -E --null-data --text -o" 102 | if [ "`uname`" = "Darwin" ]; then 103 | GH_GREP="grep -E --text -o" 104 | fi 105 | 106 | # 107 | # Grabber of the TOC from rendered html 108 | # 109 | # $1 — a source url of document. 110 | # It's need if TOC is generated for multiple documents. 111 | # 112 | gh_toc_grab() { 113 | # find strings that corresponds to template 114 | $GH_GREP \ 115 | '\s*]*>\s*\s*.*?\s*//g' | sed 's/<\/code>//g' | 122 | # now all rows are like: 123 | #

... .*<\/h/)+2, RLENGTH-5)"](" gh_url substr($0, match($0, "href=\".*\" ")+6, RLENGTH-8) ")"}' | sed 'y/+/ /; s/%/\\x/g')" 127 | } 128 | 129 | # 130 | # Returns filename only from full path or url 131 | # 132 | gh_toc_get_filename() { 133 | echo "${1##*/}" 134 | } 135 | 136 | # 137 | # Options hendlers 138 | # 139 | gh_toc_app() { 140 | local app_name="gh-md-toc" 141 | 142 | if [ "$1" = '--help' ] || [ $# -eq 0 ] ; then 143 | echo "GitHub TOC generator ($app_name): $gh_toc_version" 144 | echo "" 145 | echo "Usage:" 146 | echo " $app_name src [src] Create TOC for a README file (url or local path)" 147 | echo " $app_name - Create TOC for markdown from STDIN" 148 | echo " $app_name --help Show help" 149 | echo " $app_name --version Show version" 150 | return 151 | fi 152 | 153 | if [ "$1" = '--version' ]; then 154 | echo "$gh_toc_version" 155 | return 156 | fi 157 | 158 | if [ "$1" = "-" ]; then 159 | if [ -z "$TMPDIR" ]; then 160 | TMPDIR="/tmp" 161 | elif [ -n "$TMPDIR" -a ! -d "$TMPDIR" ]; then 162 | mkdir -p "$TMPDIR" 163 | fi 164 | local gh_tmp_md=$(mktemp $TMPDIR/tmp.XXXXXX) 165 | while read input; do 166 | echo $input >> $gh_tmp_md 167 | done 168 | gh_toc_md2html "$gh_tmp_md" | gh_toc_grab "" 169 | return 170 | fi 171 | 172 | for md in "$@" 173 | do 174 | echo "" 175 | gh_toc "$md" "$#" 176 | done 177 | 178 | echo "" 179 | echo "Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc)" 180 | } 181 | 182 | # 183 | # Entry point 184 | # 185 | gh_toc_app "$@" 186 | -------------------------------------------------------------------------------- /style/javascript.md: -------------------------------------------------------------------------------- 1 | # JavaScript Style Guide 2 | 3 | ---------- 4 | 5 | ## Linting, Formatting, and TypeChecking 6 | 7 | We use [Prettier](https://prettier.io/) for formatting our code. You shouldn't need to stress about how your code is formatted, just let Prettier do its job. 8 | 9 | We also use [ESLint](https://eslint.org/) to enforce a number of rules (some of which are mentioned here, some of which are clarified by other documentation). 10 | 11 | We highly recommend that you don't ignore ESLint errors, nor ignore TypeScript errors (as both of 12 | those could be preventing serious issues from appearing). 13 | 14 | ## Syntax 15 | 16 | ### Naming 17 | 18 | ```js 19 | ClassNamesLikeThis 20 | ComponentNamesLikeThis 21 | methodNamesLikeThis 22 | variableNamesLikeThis 23 | parameterNamesLikeThis 24 | propertyNamesLikeThis 25 | SYMBOLIC_CONSTANTS_LIKE_THIS 26 | ``` 27 | 28 | ### File names 29 | 30 | We exclusively use `.ts` and `.tsx` file extensions, as we use TypeScript. 31 | 32 | Files should be formatted like so: 33 | 34 | ```sh 35 | file-names-like-this.tsx 36 | test-files-like-this.test.tsx 37 | test-files-like-this.stories.tsx 38 | ``` 39 | 40 | ### Imports 41 | 42 | **Module System** 43 | We exclusively use ES2015 imports (`import foo from 'foo'` or `import('foo')`). 44 | 45 | Don't worry about the import order, we prefer using a tool to handle this for us, like: 46 | 47 | * [Prettier Sort Imports Plugin](https://github.com/IanVS/prettier-plugin-sort-imports) 48 | * [ESLint Sort Imports](https://eslint.org/docs/latest/rules/sort-imports) 49 | 50 | ---------- 51 | 52 | ## Comments and documentation 53 | 54 | ### Inline Comments 55 | 56 | Inline comments should be of the `//` variety, not the `/* */` 57 | variety. 58 | 59 | ### Top level file, class, and component comments 60 | 61 | All files, classes, and components should have a comment (if a file only has a single class or component, then there's no need for an extra comment for the whole file). 62 | 63 | Ideally, we should use a JSDoc-style comment, so that IDEs can pick them up for display. You 64 | don't, necessarily, have to worry about documenting each argument (or prop), you can rely upon 65 | TypeScript for that, instead. 66 | 67 | Syntax: 68 | 69 | ```js 70 | /** 71 | * A comment should begin with a slash and 2 asterisks. 72 | */ 73 | ``` 74 | 75 | Top-level (top-of-file) comments are designed to orient readers 76 | unfamiliar with the code to what is in this file and any other 77 | disclaimers clients of the code should be given. It should provide a 78 | description of the file's contents and any dependencies or 79 | compatibility information. As an example: 80 | 81 | ```js 82 | /** 83 | * Various components to handle management of lists of coaches for 84 | * the profile page. 85 | * 86 | * These utilities were not written to be a general purpose utility 87 | * for the entire code base, but has been optimized with the 88 | * assumption that the Profile namespace is fully loaded. 89 | */ 90 | ``` 91 | 92 | ### Methods and properties comments 93 | 94 | All non-trivial methods and properties should also have a comment. 95 | 96 | ---------- 97 | 98 | ## Core language rules 99 | 100 | ### Equality 101 | 102 | Prefer `===` (strict equality) to `==` due to the [numerous oddities 103 | related to JavaScript's type coercion](https://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/). 104 | 105 | The only valid use of `==` is for comparing against null and undefined 106 | at the same time: 107 | 108 | ```js 109 | // Check null and undefined, but distinguish between other falsey values 110 | if (someVariable == null) { 111 | ``` 112 | 113 | Though you will often want to just check against falsey values, and 114 | can just say `if (!someVariable) {...}`. 115 | 116 | ### Array and Object literals 117 | 118 | Always use `[]` and `{}` style literals to initialize arrays and 119 | objects, not the `Array` and `Object` constructors. 120 | 121 | Array constructors are error-prone due to their arguments: `new 122 | Array(3)` yields `[undefined, undefined, undefined]`, not `[3]`. 123 | 124 | To avoid these kinds of weird cases, always use the more readable 125 | array literal. 126 | 127 | Object constructors don't have the same problems, but follow the same 128 | rule for consistency with arrays. Plus, `{}` is more readable. 129 | 130 | ### Use a new statement for each declaration 131 | 132 | Yes: 133 | 134 | ```js 135 | const a = "foo"; 136 | const b = a + "bar"; 137 | const c = fn(a, b); 138 | ``` 139 | 140 | No: 141 | 142 | ```js 143 | const a = "foo", 144 | b = a + "bar", 145 | c = fn(a, b); 146 | ``` 147 | 148 | A single `const` statement is bad because: 149 | 150 | * If you forget a comma, you just made a global 151 | * It originated when people wanted to save bytes, but we have a minifier 152 | * It makes line-based diffs/editing messier 153 | * It encourages C89-style declarations at the top of scope, preventing 154 | you from only declaring vars before first use, the latter preferable 155 | as it conveys intended scope to the reader 156 | 157 | ### Use modules, not global variables 158 | 159 | In all of our major JavaScript repositories, we use some form of module system. 160 | 161 | In all of these cases, there are mechanisms for an explicit 162 | import/export mechanism rather than using global variables to export 163 | functionality. 164 | 165 | Yes: 166 | 167 | ```js 168 | export default class Cat { 169 | pet() { 170 | // ... 171 | } 172 | meow() { 173 | // ... 174 | } 175 | } 176 | ``` 177 | 178 | No: 179 | 180 | ```js 181 | window.Cat = { 182 | welcome() { 183 | // ... 184 | }, 185 | haveFever() { 186 | // ... 187 | } 188 | }; 189 | ``` 190 | 191 | You can export multiple objects in one file, but consider if it 192 | wouldn't be better to split up the file to maintain one export per file. 193 | 194 | ---------- 195 | 196 | ## Library rules 197 | 198 | ### Use `khanFetch()` instead of `fetch()` 199 | 200 | We now provide a polyfill for the [`fetch()` method](https://developer.mozilla.org/en-US/docs/Web/API/GlobalFetch/fetch). We should use this for all network requests. We wrote a wrapper around `fetch()` which adds in some Khan Academy-specific logic (such as adding cachebusting parameters and handling auth correctly). The interface to `khanFetch()` is exactly the same as the normal `fetch()` function. You can use it like: 201 | 202 | ```js 203 | import {khanFetch} from "~/data-access/khan-fetch.js"; 204 | ``` 205 | 206 | ### Prefer to not use Underscore or Lodash 207 | 208 | We use modern ECMAScript which includes many of the features of Underscore or Lodash! Using these libraries should be avoided in favor of these native language features. 209 | 210 | There are a couple of methods that are sufficiently complicated and don't have a direct equivalent so instead we import a couple `lodash` methods directly, you can see which ones exist in the `package.json` file. 211 | -------------------------------------------------------------------------------- /configs/KhanAcademyAndroid.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 25 | -------------------------------------------------------------------------------- /style/ios.md: -------------------------------------------------------------------------------- 1 | # iOS Style Guide 2 | 3 | We have guidelines both for [code style](#code-style-guide) and for [architectural style](#architectural-style-guide). 4 | 5 | ## Code Style Guide 6 | 7 | Hosted [externally](https://github.com/Khan/objective-c-style-guide) to this document. 8 | 9 | TODO(andy): Make a Swift code style guide. 10 | TODO(andy): Incorporate both style guides here. 11 | 12 | ## Architectural Style Guide 13 | 14 | Think of these tenets as "forces" which may push your designs incrementally in various directions. Other forces (like readability, expediency, performance, etc.) may push harder! 15 | 16 | TODO(andy): Flesh out sections with more examples and rationale. 17 | 18 | ### Don't repeat yourself 19 | 20 | Starting with a softball here: we should not repeat ourselves. 21 | 22 | We most often think of this in terms of code, where we should be careful of repeating even small idioms like `if (something) obj.doAThing()`. But it also applies to *knowledge* and *high-level structure*. 23 | 24 | We should not encode *semantic knowledge* (like "the image's size must be set before you can start the renderer"), even indirectly, in multiple places. This is particularly true when that knowledge relates to business logic. 25 | 26 | We should be on the lookout for repeated *high-level structures*: sets of statements or even subgraphs of instances which are *shaped* the same way, though they might resist abstraction via a simple parameter, often represent a liability or impediment. Sometimes straightforward patterns or abstractions can resolve these cases (e.g. `map`, the observer pattern); at other times, the cost of abstraction is perhaps too high for us to pay (e.g. applicative functors). 27 | 28 | ### Separate concerns 29 | 30 | Strive to make a given component responsible for only one thing. This makes components more composable, easier to evolve, and more testable. This is often called the [single responsibility principle](http://en.wikipedia.org/wiki/Single_responsibility_principle) 31 | 32 | ### Prefer composition to implementation inheritance 33 | 34 | Implementation inheritance creates coupling between child classes' implementations and the parent classes. When possible, make a new type with a *has-a* relationship to another type, rather than an *is-a* relationship to another type. 35 | 36 | *Interface* inheritance (i.e. via protocols) does not suffer from this problem. 37 | 38 | ### Prefer values to references 39 | 40 | Values are [inherently inert, isolated, and interchangeable](http://www.objc.io/issue-16/swift-classes-vs-structs.html). When possible, build abstractions using value types instead of using reference types. When a reference type is required (because what you're building is intentionally not inert), consider breaking the type's logic out into value types. 41 | 42 | When you can't use a value type, try to minimize mutability in your reference types to achieve a closer approximation to isolation and interchangeability. 43 | 44 | ### Prefer tree-like object graphs 45 | 46 | Avoid constructing object graphs in which objects have multiple long-lived owners. The API contract of these objects becomes much more complicated because it must specify how responsibility is divided between the owners. 47 | 48 | ### Isolate mutation: data flows downwards; events flow upwards 49 | 50 | It should always be clear where the "true" source of any piece of data is, relative to any piece of your application. Strive to thread that data linearly down to dependent components. 51 | 52 | Isolate mutation by passing events or requested changes back up the object graph from leaves to "the source of truth." 53 | 54 | ### Minimize hard coupling 55 | 56 | Consider minimizing the number of concrete types referenced and instantiated in a given implementation. This is often called the [dependency inversion principle](http://en.wikipedia.org/wiki/Dependency_inversion_principle). 57 | 58 | Minimizing the number of concrete types *referenced* is about working in terms of interfaces, not implementations. Push to replace references to concrete types with generics or protocols, especially with the standard library, where you might define interfaces in terms of `SequenceType` instead of `Array`. 59 | 60 | Dependency injection can help minimize the number of concrete types *instantiated* within an implementation. You can also pass around factory interfaces instead of instances. 61 | 62 | This tenet helps make our components more composable, makes the object graph easier to change over time, and allows for simpler, higher-quality tests. 63 | 64 | ### Isolate UIKit and Core Data 65 | 66 | Interactions with these frameworks embody a complex responsibility; their vended types often create inter-component dependencies. Implementations which interact with UIKit or Core Data should strive to have *only* that responsibility. 67 | 68 | #### Decomposing view controllers 69 | 70 | `UIViewController`s often entangle many responsibilities: 71 | 72 | 1. Receiving lifecycle and system events from UIKit and instantiating `UIView`s; handling user-interaction gestures. 73 | 2. Transforming model data for presentation. 74 | 3. Performing side effects (e.g. network requests, I/O) in response to user actions. 75 | 76 | Try to restrict subclasses to responsibility #1. Not sure how to go about decomposing your view controller's responsibility? One coarse split to start from: split #2 out into a (easily testable) value-typed "presenter" component to transform model data, and #3 into a reference-typed "interactor" component to interact with side effects like network requests or I/O. 77 | 78 | ### Minimize secret handshakes between types 79 | 80 | Try to avoid calling methods on another type which are less visible than that type itself. This increases testability and forces us to think clearly about our interfaces. We're not going to do [design by contract](http://en.wikipedia.org/wiki/Design_by_contract), but this helps us get marginally closer. 81 | 82 | ```swift 83 | public struct GuideDemo { 84 | public func demo() { 85 | PublicType().public() // A-OK 86 | PublicType().internal() // Secret handshake alarm! 87 | 88 | InternalType().internal() // A-OK 89 | InternalType().private() // Secret handshake alarm! 90 | 91 | internal() // A-OK, since this is called on self. 92 | private() // A-OK, since this is called on self. 93 | } 94 | 95 | internal func internal() {} 96 | private func private() {} 97 | } 98 | 99 | public struct PublicType { 100 | public func public() {} 101 | internal func internal() {} 102 | } 103 | 104 | internal struct InternalType { 105 | internal func internal() {} 106 | private func private() {} 107 | } 108 | ``` 109 | 110 | ### Expose the simplest interfaces 111 | 112 | Don't expose more than you have to in a type's interface. If you're passing a complex type to a consumer which uses only a small subset of its functionality, consider using a [facade](http://en.wikipedia.org/wiki/Facade_pattern). This minimizes coupling and makes components easier to evolve. Taken to an extreme, this is the [interface segregation principle](http://en.wikipedia.org/wiki/Interface_segregation_principle), but we don't need to be quite so authoritarian. 113 | 114 | #### Minimize use of `Optional`s 115 | 116 | Only use `Optional`s when the semantic you really intend is: there's a value here sometimes; and there isn't a value here sometimes. When possible, isolate the optionality so that the highest scope is non-optional. 117 | 118 | When the semantic you intend is more specific (i.e. "nil" has a special interpretation or is a sentinel), use a custom `enum` instead. 119 | 120 | ### Use simple higher-order transformations when possible 121 | 122 | Prefer `map`, `filter`, `reduce`, `sum`, `max`, etc. to ad-hoc implementations of those transformations. 123 | 124 | Avoid more esoteric higher-order transformations (e.g. `scan`, `span`, etc). 125 | 126 | ### A broad heuristic: think "how would I test this?" 127 | 128 | Prefer architectural approaches which allow you to test a component in isolation, by passing values to some interface and looking at its return values. 129 | 130 | Avoid architectural approaches which will require you to test a component in conjunction with several other components, or by configuring and observing state external to the component. 131 | 132 | A few strategies which help components be useful in isolation: 133 | 134 | * moving more functionality to the value layer (aka playing ["the value layer game"](https://realm.io/news/andy-matuschak-controlling-complexity/)) 135 | * using dependency injection 136 | * making methods `static` or free 137 | -------------------------------------------------------------------------------- /style/python.md: -------------------------------------------------------------------------------- 1 | # Python 2 | 3 | We follow the [PEP8 style guide for Python](http://www.python.org/dev/peps/pep-0008/). Docstrings follow [PEP257](http://www.python.org/dev/peps/pep-0257/). The rest of the document describes additions and clarifications to the PEP documents that we follow at Khan Academy. 4 | 5 | You can use `make lint` from the top level of the website source tree to run a pep8 check over all the source code or `make linc` to check only files you've changed. You should aim to not introduce any new violations, before checking in code. 6 | 7 | ## Indentation 8 | 9 | Use 4 spaces -- never tabs -- for indentation. 10 | 11 | This is a strict rule and ignoring this can (has) cause(d) bugs. 12 | 13 | ## \_\_init\_\_.py 14 | 15 | Unless an exception is explicitly allowed by a codebase owner (Kamens or Jason, for now), `__init__.py` files should be empty. 16 | 17 | > *Rationale:* when you do `import foo.bar` python imports two files: `foo/bar.py`, and `foo/__init__.py`. If `foo/__init__.py` has imports of its own, those will be run as well -- even if you don’t plan to run any of the code defined in `__init__.py`. This slows down execution, and worse causes circular-import problems that could be entirely avoided. 18 | 19 | If you have code that you think every user of every function inside this directory needs to run first, `__init__.py` may be appropriate, but you should also consider just creating a function that executes that code, and running the function at the top level (that is, not indented) inside each file in your directory. This makes it more obvious what's going on, and also makes it easier to special-case certain files if the need ever arises. 20 | 21 | Using `__init__.py` to bring variables from sub-modules into the main module space totally defeats the point of having sub-modules in the first place; don’t do it. 22 | 23 | For more discussion, see http://stackoverflow.com/questions/1944569/how-do-i-write-good-correct-init-py-files. 24 | 25 | ## Imports 26 | 27 | ### from...import 28 | 29 | Only import entire modules, never individual symbols from a module. For top-level modules, that means `import foo`. For sub-modules, you can do either `import foo.bar` or `from foo import bar`. 30 | ```py 31 | import auth_util # module import: importing the file auth_util.py 32 | import auth.oauth_credentials # module import: importing the file auth/oauth_credentials.py 33 | from auth import oauth_credentials # module import: importing the file auth/oauth_credentials.py 34 | from auth_util import get_response # BAD: symbol import: importing the function get_response from auth_util.py 35 | from auth_util import Authorize # BAD: symbol import: importing the class Authorize from auth_util.py 36 | from auth_util import AUTH_HOST # BAD: symbol import: importing the variable AUTH_HOST from auth_util.py 37 | ``` 38 | *Exception:* for third-party code, where the module documentation explicitly says to import individual symbols. 39 | 40 | If the basename of a sub-module is generic, prefer the import form to the from form, otherwise either is fine: 41 | 42 | ```py 43 | import auth.models # code uses auth.models.Token -- clear 44 | 45 | from auth import models # code uses models.Token -- ambiguous! 46 | 47 | from auth import oauth_credentials # code uses oauth_credentials.Token -- clear 48 | ``` 49 | 50 | > Rationale: This is the single best -- and easiest -- way to avoid the circular-import problem. To simplify, when you say `import x`, Python executes the `x.py` file, but doesn't need to get any attributes from it. When you say `from x import foo`, Python needs `x.py` to be executed enough that `foo` is defined in it. When `x` does a 'from-import' from `y`, and `y` does a 'from-import' from `x`, the circular import can succeed if a partial module is enough (as it will be with `import x`), but it can fail if the circularity happens before the needed attribute is defined (as it might be with `from x import foo`). 51 | 52 | > Second rationale: Mocking of symbols doesn't work when importing the symbols. The end result is often a mix of importing modules and symbols, but it isn't clear when the import style matters (for mocking) and when it is just for convenience. 53 | 54 | > *Side note:* While this rule helps with most circular-import problems, it doesn’t help with all: a module `x` may still need symbols from a module `y` while `x` is still being imported. For instance, if you say `class xclass(y.yclass): ...`, Python needs the `yclass` attribute at import-time. 55 | 56 | The downside of this rule is that code gets more verbose: where before you could do 57 | 58 | ```py 59 | from possibly_a_very_long_name import MyClass 60 | [...] 61 | m = MyClass(...) 62 | ``` 63 | 64 | now you have to do 65 | 66 | ```py 67 | import possibly_a_very_long_name 68 | [...] 69 | m = possibly_a_very_long_name.MyClass(...) 70 | ``` 71 | 72 | I argue, though, this verbiage is beneficial: in the same way that self.xxx is an immediate sign at the point of use that xxx is a member of the current class, x.MyClass is an immediate sign that MyClass comes from file x (which often tells you more about what MyClass is for, and makes it easier to find in the source as well). This often tells you enough that you can continue reading the code, without needing a context switch to look up the where MyClass is defined and what it says. 73 | 74 | ### absolute_import 75 | 76 | Always use `from __future__ import absolute_import` as the first 77 | import in your source file. Do not use relative imports (`from 78 | . import foo`) unless you have to. 79 | 80 | > *Rationale:* Suppose you have both `intl.py` and 81 | `content/videos/intl.py`, and you say `import intl` in your source 82 | file. Without absolute-imports, what gets imported depends on where 83 | your source file lives (in content/videos or elsewhere), which is 84 | confusing. By making all imports be related to the repository-root, 85 | it avoids ambiguity, making it easier for code readers -- and code 86 | writers! -- to figure out the exact file that's being imported. 87 | 88 | The reason not to use relative imports is to avoid two ways of doing 89 | things: some people importing a module as an absolute path and some as 90 | a relative path makes it harder for readers to understand, harder to 91 | do tooling, and so forth. (We could have settled on _always_ using 92 | relative imports, but combining the two does not make sense.) 93 | Sometimes, when you're doing fancy things with import hooks or the 94 | like you have to use relative imports, but minimize these cases. 95 | 96 | This means that all non-system imports will be specified relative to 97 | the root of the KA python tree. 98 | 99 | ### Import style 100 | 101 | All imports should be at the top of the file, separated (by blank lines) into three sections: system imports, third-party imports (including appengine), and khan academy-written imports. Note that imports from `third_party` and `shared` are considered "third party" even if they are maintained by Khan Academy and only used in webapp. 102 | 103 | > *Rationale:* When I see autocomplete.foo() in the code, and I want to know what it does, it’s helpful to know if I should be looking on the web (because autocomplete is part of the python distribution), or in the local source tree (because autocomplete is written by us). It’s also helpful to know if it’s code we wrote (and the barrier to hacking on it is low) or code someone else wrote (which means it may be easier to just work around any problems I have with it). The three sections tell me that with just a quick glance at the top of the file. Plus, since each section is alphabetical, it’s easy for me to find the import within the section. 104 | 105 | Alphabetical sorting is by the main module name (so second word of the line), and ignores case: 106 | 107 | ```py 108 | import api 109 | from app import App 110 | from app import Zebra 111 | import auth_models 112 | import NonExistentModule 113 | [...] 114 | ``` 115 | 116 | Here are some constructs that are not consistent with this style rule: 117 | ```py 118 | from app import App, Zebra # BAD: two imports on the same line 119 | import .models # BAD: relative import. Alternative: from import models 120 | ``` 121 | 122 | ## Docstrings 123 | 124 | All non-trivial methods should have docstrings. Docstrings should follow guidelines here: [PEP257](http://www.python.org/dev/peps/pep-0257/). For more examples, see the [Google style guide](https://google.github.io/styleguide/pyguide.html#Comments) around docstrings. 125 | 126 | To summarize: There are two types of docstrings, long-form and short-form. 127 | 128 | A short-form docstring fits entirely on one line, including the triple quotes. It is used for simple functions, especially (though by no means exclusively) ones that are not part of a public API: 129 | 130 | ```py 131 | """Return a user-readable form of a Frobnozz, html-escaped.""" 132 | ``` 133 | 134 | Note that the text is specified as an action (“return”) rather than a description (“returns”). This has the added advantage of taking less space, so the comment is more likely to fit on a single line. :-) 135 | 136 | If the description spills past one line, you should move to the long-form docstring: a summary line (one physical line) starting with a triple-quote ("""), terminated by a period, question mark, or exclamation point, followed by a blank line, followed by the rest of the doc string starting at the same cursor position as the first quote of the first line, ending with triple-quotes on a line by themselves. (Unlike what the BDFL suggests in PEP 257, we do not put a blank line before the ending quotes.) 137 | 138 | ```py 139 | """This comment serves to demonstrate the format of a docstring. 140 | 141 | Note that the summary line is always at most one line long, and 142 | on the same line as the opening triple-quote, and with no spaces 143 | between the triple-quote and the text. Always use double-quotes 144 | (") rather than single-quotes (') for your docstring. (This 145 | lets us reserve ''' (3 single-quotes) as a way of commenting out 146 | big blocks of code. 147 | """ 148 | ``` 149 | 150 | A function (including methods and generators) must have a docstring, unless it meets all of the following criteria: 151 | 152 | - not externally visible 153 | - very short 154 | - obvious 155 | 156 | The docstring should describe the function's calling syntax and its semantics, not its implementation. 157 | 158 | The docstring should end with the following special sections (see [the Google style guide](https://google.github.io/styleguide/pyguide.html?showone=Comments#Comments) for more details). 159 | 160 | - **Arguments:** List each parameter by name, and a description of it. The description can span several lines (use a hanging indent if so). Use instead of "Args". 161 | - **Returns:** (or **Yields:** for generators): Describe the type and semantics of the return value. If the function only returns None, this section is not required. 162 | - **Raises:** List all exceptions that are relevant to the interface. 163 | 164 | Classes should follow a similar format: a single line describing the class, plus more details, but instead of Arguments/Returns/Raises, it should have an Attributes: section that lists and describes the public attributes of the class (if any). 165 | 166 | Modules (files) should have a docstring too, at the top of the file, starting with the usual one-line summary: 167 | ```py 168 | """One line summary. 169 | 170 | Longer description. 171 | """ 172 | ``` 173 | 174 | > Rationale: People will read a piece of code many more times than they will write it. Time spent documenting at write-time more than pays off at read time. What is obvious to you as the code-author, well versed in the module where this function lives, may not be at all obvious to a code reader, who is possibly jumping into this function from some unrelated part of the codebase. 175 | 176 | The rules here may seem like overkill, especially the need to document every argument and return value. I can say from experience two things: it often does seem like overkill when writing it (especially when the docstring is longer than the function!) but I've almost never thought it was overkill when reading unfamiliar code. You may find, as you write the docstring, you're putting down something that wasn't as obvious as you thought it was: 177 | 178 | ```py 179 | def WriteTimestamp(now): 180 | """Write the current time to stdout in an arbitrary user-readable format. 181 | 182 | Arguments: 183 | now: the current time as a time_t. Should be time.time() except for tests. 184 | """ 185 | ... 186 | ``` 187 | 188 | Even though the meaning of now may seem obvious, it's not obvious that it's only being passed in so it can be mocked out for tests. Its type also isn't obvious (a time_t? a tuple? a datetime object?), so it's nice to have that documented as well. 189 | 190 | ## Top of the file 191 | 192 | Start your file with a module docstring. Do not put a shebang line (`#!/usr/bin/python`) or copyright notice, or anything else. Follow the docstring with your imports; don't put an `__author__` line. 193 | 194 | > *Exception:* if the python file is meant to be executable, it should start with the following shebang line: 195 | 196 | >```py 197 | >#!/usr/bin/env python 198 | >``` 199 | 200 | > *Rationale:* a shebang line is useless for non-executable files. An `__author__` line just gets out of date, and is better determined by looking at source control history in any case. Code is automatically copyrighted; a copyright line doesn't help. No need to put this useless boilerplate at the top of the file! 201 | 202 | TODO(csilvers): should we put in a line indicating licensing? 203 | 204 | ## Symbol naming 205 | 206 | When naming a top-level symbol -- function, class, or variable -- use 207 | a leading underscore if the symbol is private to the module: that is, 208 | nobody may reference that symbol except for code in the module itself 209 | and its associate test file(s). 210 | 211 | Modules themselves may have names starting with a leading underscore 212 | to mean that all symbols in that module are private to the _package_ 213 | the symbols is in. A "package" is basically the top-level directory 214 | that the module is under, within webapp. (Example packages are 215 | "content", "login", and "missions.") Note that an underscored symbol 216 | within an underscored module is still considered private to the 217 | module. 218 | 219 | Inside a class, use a leading underscore to indicate a symbol (method 220 | or class variable) is private to that class and its subclasses. If 221 | you want a symbol to be private to the class itself, and not even 222 | visible to subclasses, use a leading double-underscore. 223 | 224 | ## Unused variables 225 | 226 | If you want to assign a value to a variable that will not be used again, name the variable either `_` (python convention) or `unused_` (less-well-known python convention). This will keep our lint checkers from complaining. 227 | 228 | ## Splitting lines 229 | 230 | Using PEP8 as a guideline for Python formatting runs us head-long into a great debate: the 79-character line limit. For better or worse, the PEP8 limit is part of the lint check for Khan Academy's Python code. 231 | 232 | > Rationale: short lines have benefits, including: 233 | 234 | > - Broad tool support. Code is read more frequently than it is written, often by those whose tools don't match the original author. Short lines are always well-supported. Many tools only naively support long lines (`
` tags and most terminal tools), and no editor wraps long lines intelligently enough in all cases.
235 | > - Side-by-side code windows. Try it out, it's great.
236 | > - A free gut check. It's easy to reach 100 or 200 columns when writing complex expressions or nesting deeply. If this indicates unclear code, future readers would appreciate a quick refactoring.
237 | 
238 | > Of course having a hard limit for line length is silly. Any reasonable limit runs into a case where breaking the rule produces better code. However, having unnecessarily long lines scattered about due to assumptions about a reader's tools is also silly.
239 | 
240 | Python expressions end with a newline, not a semicolon, unlike many C-based languages. The trick is that lines can be continued within parentheses, brackets, and braces, or following a backslash. Parentheses are recommended. Backslashes should be avoided.
241 | 
242 | ```py
243 | >>> True and (True or
244 | ...           False)
245 | 
246 | 
247 | >>> [x * x
248 | ...  for x
249 | ...  in xrange(0, 10)
250 | ...  if x % 2]
251 | 
252 | 
253 | >>> {'Earth': 1,
254 | ...  'Jupiter': 5.3,
255 | ...  'Saturn': 9}
256 | ```
257 | 
258 | Notably, splitting string literals doesn't require use of the + operator. Adjacent literals are automatically combined.
259 | 
260 | ```py
261 | >>> twist = 'Peter Piper ' 'split a set ' 'of simple strings'
262 | >>> twist
263 | 'Peter Piper split a set of simple strings'
264 | ```
265 | 
266 | This makes splitting long messages easy.
267 | 
268 | ```py
269 | >>> twist = ('Peter Piper '
270 | ...          'split a set '
271 | ...          'of simple strings')
272 | ```
273 | 
274 | Because Python's indentation style is unlike many C-based languages, your editor might need some cajoling to support it.
275 | 
276 | - Emacs has great support out of the box via `python-mode`.
277 | - Vim needs some help. Installing [this indent script by Eric Mc Sween](http://www.vim.org/scripts/script.php?script_id=974) will get you there.
278 | 
279 | Examples of line splitting from our code:
280 | 
281 | ```py
282 | BAD:  zero_duration_videos = video_models.Video.all().filter("duration =", 0).fetch(10000)
283 | 
284 | GOOD: zero_duration_videos = (video_models.Video.all()
285 |                         .filter("duration =", 0)
286 |                         .fetch(10000))
287 | ```
288 | 
289 | ```py
290 | # BAD:
291 | return current_app.response_class("OAuth error. %s" % e.message, status=401, headers=build_authenticate_header(realm="http://www.khanacademy.org"))
292 | 
293 | # GOOD:
294 | return current_app.response_class(
295 |     "OAuth error. %s" % e.message, status=401,
296 |     headers=build_authenticate_header(realm="http://www.khanacademy.org"))
297 | ```
298 | 
299 | ```py
300 | # Bad:
301 | kwargs = dict((str(key), value) for key, value in topic_json.iteritems() if key in ['id', 'title', 'standalone_title', 'description', 'tags', 'hide'])
302 | # Good:
303 | kwargs = dict((str(key), value)
304 |               for key, value in topic_json.iteritems()
305 |               if key in ['id', 'title', 'standalone_title',
306 |                          'description', 'tags', 'hide'])
307 | ```
308 | 
309 | ## Splitting tricky lines
310 | 
311 | There are cases where line splitting doesn't feel nice. Let's look at a few of them, sigh, and move on.
312 | 
313 | This long method reference needs surrounding parens and splits the line before the dot operator:
314 | 
315 | ```py
316 | # Bad:
317 | badge_name = badges.topic_exercise_badges.TopicExerciseBadge.name_for_topic_key_name(self.key().name())
318 | # Good:
319 | badge_name = (badges.topic_exercise_badges.TopicExerciseBadge
320 |               .name_for_topic_key_name(self.key().name()))
321 | ```
322 | 
323 | This long string path needs to be split.
324 | 
325 | ```py
326 | # Bad:
327 | self.redirect("/class_profile?selected_graph_type=%s&coach_email=%s&graph_query_params=%s" %
328 |         (self.GRAPH_TYPE, urllib.quote(coach.email), urllib.quote(urllib.quote(self.request.query_string))))
329 | # Good:
330 | self.redirect(
331 |     "/class_profile?selected_graph_type=%s&coach_email=%s"
332 |     "&graph_query_params=%s" % (
333 |         self.GRAPH_TYPE,
334 |         urllib.quote(coach.email),
335 |         urllib.quote(urllib.quote(self.request.query_string))))
336 | ```
337 | 
338 | Sometimes, the best way to avoid long lines is to use temporary variables.  This can improve readability in any case.
339 | 
340 | ```py
341 | # Bad:
342 | topics_list = [t for t in topics if not (
343 |     (t.standalone_title == "California Standards Test: Algebra I" and t.id != "algebra-i") or
344 |     (t.standalone_title == "California Standards Test: Geometry" and t.id != "geometry-2"))
345 |     ]
346 | # Good:
347 | bad_title_and_ids = [("California Standards Test: Algebra I", "algebra-i"),
348 |                      ("California Standards Test: Geometry", "geometry-2"),
349 |                     ]
350 | topics_list = [t for t in topics
351 |                if not (t.standalone_title, t.id) in bad_title_and_ids]
352 | ```
353 | 
354 | ## Indenting continued lines properly
355 | 
356 | When a logical statement is split into multiple lines and is followed by an indented line, the continued lines should be indented further to set them apart from the next logical statement.
357 | 
358 | In the following example taken from http://www.python.org/dev/peps/pep-0008/#maximum-line-length, notice how the second and third lines of the if condition are indented further to differentiate them from the actual raise statement within the if block:
359 | 
360 | ```py
361 | class Rectangle(Blob):
362 |     def __init__(self, width, height,
363 |                      color='black', emphasis=None, highlight=0):
364 |         if (width == 0 and height == 0 and
365 |                 color == 'red' and emphasis == 'strong' or
366 |                 highlight > 100):
367 |             raise ValueError("sorry, you lose")
368 | ```
369 | 
370 | ## Classes
371 | 
372 | Use classes primarily as a container for data.  You can use methods
373 | for functionality that is "core" to the purpose of a class -- one way
374 | to tell is if that method has a lot of callers, rather than just one
375 | or two -- or when needed for method-name dispatch (e.g., having a
376 | bunch of different classes define their own `get_search_data()` so a
377 | function can call `node.get_search_data()` and get the right function
378 | for that node-type), but try to keep them to a minimum.  Prefer
379 | top-level functions instead.
380 | 
381 | > Rationale: in Python, the implementation of a class needs to be in a
382 |   single file.  If you have a class with many methods
383 |   doing many different things, each with its own set of dependencies,
384 |   then the file defining that class ends up with a huge number of
385 |   dependencies.  This can make the class hard to use, since importing
386 |   it may cause circular imports -- or at the least, bloat your
387 |   dependency graph.
388 | 
389 | For the same reason, prefer one class per file.  (You can make
390 | exceptions for classes that are very closely related, or a class that
391 | is used primarily as a member of another class.)
392 | 
393 | 


--------------------------------------------------------------------------------
/style/android-development-best-practices.md:
--------------------------------------------------------------------------------
  1 | ## Prefer Immutability
  2 | 
  3 | Our principal goal as programmers is to reduce complexity. At any point in a program, we can reason about the state of a constant trivially -- its state is the state upon assignment. By contrast, the state of a variable can change endlessly.
  4 | 
  5 | With judicious use, immutable objects can lead to quicker execution speed and lower memory usage. The hash value of a `String`, the query parameters of an immutable URL, and the distance traced by an immutable sequence of points are all immutable as well. We can cache their values for later use instead of recompute them on every access. We can also share an immutable object with clients without requiring those clients to defensively copy it.
  6 | 
  7 | An immutable value is safe in many ways. For example, `String` is immutable and so its `hashCode` value is immutable. Consequently, it is safe to use as a `String` as a key in a `Map`: The lower order bits of that hash will never change, and so an inserted key will never reside in the wrong bucket. An immutable value is also thread-safe, because a client must acquire a lock only to read data that another client can concurrently modify. An immutable value renders that moot.
  8 | 
  9 | A good approach for creating immutable types is to define types that are simply data, and which do not have behavior. For example, consider the `SecondsWatched` class, which tracks the seconds watched values in a video:
 10 | 
 11 | ```java
 12 | public class SecondsWatched {
 13 |     public final long lastSecondWatched;
 14 |     public final long totalSecondsWatched;
 15 | 
 16 |     public SecondsWatched(long lastSecondWatched, long totalSecondsWatched) {
 17 |         /* Preconditions checks here... */
 18 | 
 19 |         this.lastSecondWatched = lastSecondWatched;
 20 |         this.totalSecondsWatched = totalSecondsWatched;
 21 |     }
 22 | 
 23 |     /* Method equals, hashCode, and toString follow here. */
 24 | }
 25 | ```
 26 | 
 27 | Note that this instance is immutable because its `lastSecondsWatched` and `totalSecondsWatched` fields are `final`, and hence cannot be reassigned.
 28 | 
 29 | The `VideoUserProgress` instance composes a `SecondsWatched` instance of this class:
 30 | 
 31 | ```java
 32 | public final class VideoUserProgress extends ContentItemUserProgress {
 33 |     public final SecondsWatched secondsWatched;
 34 |     public final Optional lastWatchedDate;
 35 | 
 36 |     /* Constructor, equals, hashCode, and toString follow here. */
 37 | }
 38 | ```
 39 | 
 40 | Again, `SecondsWatched` is immutable. So is an instance of the `Date` class. A constructed `Optional` cannot be reassigned to refer to another (possibly `null`) value, and so it is immutable as well. By virtue of the `VideoUserProgress` composing instances of immutable classes, and making those fields `final`, then each `VideoUserProgress` instance is immutable as well.
 41 | 
 42 | Note that for such immutable classes, we do not provide getter methods for each field. Instead, these fields are have `public` visibility. This is because getter methods are typically paired with corresponding setter methods for access control, but immutable values can by definition not be set.
 43 | 
 44 | ## Prefer interfaces over implementations
 45 | 
 46 | The Java standard library has a rich suite of interfaces for collections: `List`, `Map`, `SortedMap`, `Set`, and `SortedSet`. The standard implementations of these interfaces include `ArrayList`, `LinkedList`, `HashMap`, `TreeMap`, `HashSet`, and `TreeSet`.
 47 | 
 48 | For their parameters and return values, method signatures should refer to the most generalizable collection type that is most appropriate. For example, consider the `VideoSubtitleSequence` class, which represents a transcript for a video:
 49 | 
 50 | ```java
 51 | public final class VideoSubtitleSequence {
 52 |   private final ImmutableList subtitles;
 53 | 
 54 |   public VideoSubtitleSequence(List subtitles) {
 55 |     this.subtitles = ImmutableList.copyOf(subtitles);
 56 |   }
 57 | 
 58 |   ...
 59 | }
 60 | ```
 61 | 
 62 | A transcript is an ordering of `VideoSubtitle` instances. Its constructor has a parameter type of `List`. It does not specify a list implementation, such as `ArrayList`:
 63 | 
 64 | ```java
 65 | public VideoSubtitleSequence(ArrayList subtitles) { ... }
 66 | ```
 67 | 
 68 | This constructor could not be invoked if the client had a value of type `List`, `LinkedList`, or some other `List` implementation. The client would have to create and populate a temporary `ArrayList` simply for the purposes of calling this method.
 69 | 
 70 | Likewise, the constructor does not choose a superinterface of `List`, such as `Collection` or `Iterable`:
 71 | 
 72 | ```java
 73 | public VideoSubtitleSequence(Collection subtitles) { ... }
 74 | ```
 75 | 
 76 | Because `Set` extends `Collection`, a client could construct a `VideoSubtitleSequence` with a `Set` of `VideoSubtitle` instances. But the iteration order for a `Set` implementation is undefined. Therefore the order in which the client adds `VideoSubtitle` instances to the set is not guaranteed, or even likely, to equal the iteration order when the video plays.
 77 | 
 78 | ## Adding a Database Table
 79 | 
 80 | If you need to persist a new type of data to SQLite, there are quite a few steps you need to go through. Fortunately, they are all quite straightforward and self-contained.
 81 | 
 82 | ### Define any table names
 83 | 
 84 | Create a new class that defines the names of any tables you need to create. You must also create a `SelectStatementSource` for each of them; this allows you to later execute queries against the table with the given name.
 85 | 
 86 | For example, the following `UserDatabaseTables` class defines a single SQLite table named `UserSession`, and creates a `SelectStatementSource` for it:
 87 | 
 88 | ```java
 89 | final class UserDatabaseTables {
 90 |   private UserDatabaseTables() {}
 91 | 
 92 |   static final class Names {
 93 |     public static final String USER_SESSION = "UserSession";
 94 |   }
 95 | 
 96 |   static final class Sources {
 97 |     public static final SelectStatementSource USER_SESSION = SelectStatementSource.table(Names.USER_SESSION);
 98 |   }
 99 | }
100 | ```
101 | 
102 | ### Define the table columns
103 | 
104 | Create a new class that defines the names of all the columns in the table. Note that here you are simply defining their names; their types are defined separately in a migration below.
105 | 
106 | For example, the following `UserDatabaseTableColumns` defines the columns for the `UserSession` table:
107 | 
108 | ```java
109 | public final class UserDatabaseTableColumns {
110 |   private UserDatabaseTableColumns() {}
111 | 
112 |   public static final class UserSessionTable {
113 |     public static final ResultColumn KAID = ResultColumn.withName("kaid");
114 |     public static final ResultColumn NICKNAME = ResultColumn.withName("nickname");
115 |     ...
116 | 
117 |     public static final List ALL_COLUMNS = ImmutableList.of(
118 |       KAID,
119 |       NICKNAME,
120 |       ...
121 |     );
122 |   }
123 | }
124 | ```
125 | 
126 | As seen above, it is also typically helpful to define a static `ALL_COLUMNS` field. This is so you can easily build a `SelectStatement` that selects all columns from rows that satisfy a given condition.
127 | 
128 | ### Define a migration
129 | 
130 | We define a *migration* any time the schema for a given table changes. When the app is first launched on a device, the table does not exist; therefore the first migration we must perform is to actually create the table.
131 | 
132 | The following shows how the migrations defined for the user database:
133 | 
134 | ```java
135 | public static List getMigrations() {
136 |   return ImmutableList.of(
137 |     rawSql("CREATE TABLE " + Names.USER_SESSION + " (" +
138 |              KAID + " TEXT PRIMARY KEY NOT NULL," +
139 |              NICKNAME + " TEXT NULL," +
140 |              IS_PHANTOM + " BOOLEAN NOT NULL," +
141 |              AUTH_TOKEN_VALUE + " TEXT NOT NULL," +
142 |              AUTH_TOKEN_SECRET + " TEXT NOT NULL," +
143 |              IS_ACTIVE + " BOOLEAN NOT NULL DEFAULT 0" +
144 |          ")"
145 |     ),
146 |     rawSql("CREATE INDEX UserSessionIsActiveIndex ON " + Names.USER_SESSION + "(" +
147 |              IS_ACTIVE +
148 |          ")"
149 |     ),
150 |     rawSql("ALTER TABLE " + Names.USER_SESSION + " ADD COLUMN " +
151 |       AVATAR_URL + " TEXT NULL"
152 |     )
153 |   );
154 | }
155 | ```
156 | 
157 | This first creates the table, and then adds an index on its `IS_ACTIVE` column. Later we decided to store the `AVATAR_URL` for a user; therefore we had to define an additional migration to add this to any existing table.
158 | 
159 | Typically you only need to define a `CREATE TABLE` migration. Also you should create any `CREATE INDEX` migrations as needed.
160 | 
161 | ### Define a transformer
162 | 
163 | If you want to persist instances of `MyClass` to your new table, then we must specify how to convert between a `MyClass` instance and the columns in the table. This is what a transformer does. There are two directions to the transformation.
164 | 
165 | When writing to the database, a `EntityToDatabaseRowTransformer` implementation converts from an instance of type `T` to the corresponding column values:
166 | 
167 | ```java
168 | public interface EntityToDatabaseRowTransformer {
169 |     Map transformEntityIntoRow(T data);
170 | }
171 | ```
172 | 
173 | When reading from the database, a `DatabaseRowToEntityTransformer` implementation converts from the column values to an instance of type `T`:
174 | 
175 | ```java
176 | public interface DatabaseRowToEntityTransformer {
177 |   T transformRowIntoEntity(Map row);
178 | }
179 | ```
180 | 
181 | For example, the `UserSessionEntityTransformer` implements both these interfaces, thereby defining both transformations for a `UserSession`:
182 | 
183 | ```java
184 | @Override
185 | public UserSession transformRowIntoEntity(final Map row) {
186 |   final User user = new User(
187 |       (String) row.get(KAID.toString()),
188 |       toBoolean(row.get(IS_PHANTOM.toString())),
189 |       (String) row.get(NICKNAME.toString()),
190 |       toUri(row.get(AVATAR_URL.toString()))
191 |   );
192 | 
193 |   return new UserSession(
194 |       new OAuthAccessToken(
195 |               (String) row.get(AUTH_TOKEN_VALUE.toString()),
196 |               (String) row.get(AUTH_TOKEN_SECRET.toString())
197 |       ),
198 |       user
199 |   );
200 | }
201 | 
202 | @Override
203 | public Map transformEntityIntoRow(final UserSession userSession) {
204 |   final Builder builder = ImmutableNullableMap.builder();
205 | 
206 |   return builder
207 |       .put(KAID.toString(), userSession.user.kaid)
208 |       .put(NICKNAME.toString(), userSession.user.nickname.orNull())
209 |       .put(IS_PHANTOM.toString(), fromBoolean(userSession.user.isPhantom))
210 |       .put(AVATAR_URL.toString(), fromUriOptional(userSession.user.avatarUrl))
211 |       .put(AUTH_TOKEN_VALUE.toString(), userSession.authToken.value)
212 |       .put(AUTH_TOKEN_SECRET.toString(), userSession.authToken.secret)
213 |       .build();
214 | }
215 | ```
216 | 
217 | ### Define a database client
218 | 
219 | We now have all the primitives needed to create and modify a table with values of some type `T`. To modify such a table, use the static factory methods or builders of the following classes to create corresponding SQLite statements:
220 | 
221 | * `SelectStatement`
222 | * `InsertStatement`
223 | * `UpdateStatement`
224 | * `DeleteStatement`
225 | 
226 | Once you have such a statement, you can execute it by passing it to the corresponding method of a `Database`. Note that if you are using a `SelectStatement`, you must pass a `DatabaseRowToEntityTransformer` parameter to convert each selected row to an instance of its corresponding type. Likewise, if you are using an `InsertStatement` or a `UpdateStatement`, you must pass a `EntityToDatabaseRowTransformer` parameter to convert each instance to the collection of column values.
227 | 
228 | For example, in the `UserDatabase` class, the following `FETCH_ALL_SESSIONS_STATEMENT` is a query that selects all columns from all rows of the `UserSession` table:
229 | 
230 | ```java
231 | private static final SelectStatement FETCH_ALL_SESSIONS_STATEMENT = SelectStatement.selectColumns(
232 |     UserSessionTable.ALL_COLUMNS,
233 |     Sources.USER_SESSION
234 | );
235 | ```
236 | 
237 | The `fetchAllUserSessions` method below executes this query against a database by invoking `fetchObjects` on its `Database` instance. Its `SESSION_TRANSFORMER` instance implements `DatabaseRowToEntityTransformer`, and thereby converts each returned row to a `UserSession` instance.
238 | 
239 | ```java
240 | public Set fetchAllUserSessions() {
241 |   return ImmutableSet.copyOf(mDatabase.fetchObjects(
242 |       FETCH_ALL_SESSIONS_STATEMENT,
243 |       SESSION_TRANSFORMER
244 |   ));
245 | }
246 | ```
247 | 
248 | Similarly, the `insertOrUpdateUserSession` method below inserts a given `UserSession` by invoking `insertOrReplaceRows` on its `Database` instance. The `Names.USER_SESSION` specifies the table to insert into, the `ImmutableList.of` static factory method creates the list of `UserSession` instances to insert, and the `SESSION_TRANSFORMER` instance implements `EntityToDatabaseRowTransformer` and thereby converts each `UserSession` instance to its row values:
249 | 
250 | ```java
251 | public void insertOrUpdateUserSession(final UserSession userSession) {
252 |   mDatabase.update(InsertStatement.insertOrReplaceRows(
253 |       Names.USER_SESSION,
254 |       ImmutableList.of(userSession),
255 |       SESSION_TRANSFORMER
256 |   ));
257 | }
258 | ```
259 | 
260 | ## Use Google Guava
261 | 
262 | From the Google Guava web page:
263 | 
264 | > The Guava project contains several of Google's core libraries that we rely on in our Java-based projects: collections, caching, primitives support, concurrency libraries, common annotations, string processing, I/O, and so forth.
265 | 
266 | Some of the packages are indispensable for disciplined Java development:
267 | 
268 | ### Preconditions
269 | 
270 | The `Preconditions` class is found in the `com.google.common.base` package. Use it in every constructor you define to ensure that a client is constructing a valid instance. By catching such invalid data when the instance is created, we can determine the source of the invalid parameters by navigating the stacktrace. If we checked for validity upon use, we not only put the burden on every client to ensure that the data is valid, and this precludes finding where the invalid data comes from.
271 | 
272 | #### Method `checkNotNull`
273 | 
274 | The `checkNotNull` method accepts a parameter and throws an `NullPointerException` if it is `null`. It returns that parameter if it is not. Use it for objects:
275 | 
276 | ```java
277 | public final class ApiClient {
278 |     public final ContentApi contentApi;
279 |     public final UserApi userApi;
280 | 
281 |     public ApiClient(ContentApi contentApi, UserApi userApi) {
282 |         this.contentApi = Preconditions.checkNotNull(contentApi);
283 |         this.userApi = Preconditions.checkNotNull(userApi);
284 |     }
285 | }
286 | ```
287 | 
288 | Therefore a client of an `ApiClient` instance can be ensured that it has `contentApi` and `userApi` fields that are not `null`. It does not need to defend itself against these conditions.
289 | 
290 | #### Method `checkArgument`
291 | 
292 | The `checkArgument` method asserts that its expression is `true`. If not, it throws an `IllegalArgumentException`. It's best to provide a second parameter that provides a more detailed message for the `IllegalArgumentException`. This message should include any parameter in the expression that evaluated as `false`. This makes debugging easier. For example: 
293 | 
294 | ```java
295 | public final class SecondsWatched {
296 |     public final long lastSecondWatched;
297 |     public final long totalSecondsWatched;
298 |   
299 | 
300 |     public SecondsWatched(long lastSecondWatched, long totalSecondsWatched) {
301 |         Preconditions.checkArgument(lastSecondWatched >= 0,
302 |                 "lastSecondWatched cannot be negative: " + lastSecondWatched);
303 |         Preconditions.checkArgument(totalSecondsWatched >= 0,
304 |                 "totalSecondsWatched cannot be negative: " + totalSecondsWatched);
305 | 
306 |         this.lastSecondWatched = lastSecondWatched;
307 |         this.totalSecondsWatched = totalSecondsWatched;
308 |     }
309 | }
310 | ```
311 | 
312 | ### Object utilities
313 | 
314 | For immutable objects that are just data and define no behavior, it's useful to implement `equals`, `hashCode`, and `toString`.
315 | 
316 | #### Implementing `equals`
317 | 
318 | The template for implementing `equals` is:
319 | 
320 | ```java
321 | public final class VideoSubtitle {
322 |     public final long timeMillis;
323 |     public final String text;
324 |     
325 |     @Override
326 |     public boolean equals(Object o) {
327 |         if (this == o) return true;
328 |         if (!(o instanceof VideoSubtitle)) return false;
329 | 
330 |         VideoSubtitle that = (VideoSubtitle) o;
331 | 
332 |         return (timeMillis == that.timeMillis
333 |                 && text.equals(that.text));
334 |     }
335 | }
336 | ```
337 | 
338 | As shown above, do not forget to use the `equals` method to compare instance fields that are objects (i.e. extend `Object`). Accidentally using `==` will test for identity, or whether both operands refer to the same object (i.e. the same instance at the same address in memory).
339 | 
340 | Defining an `equals` method is especially useful for testing, as it allow us to leverage the `assertEquals` method:
341 | 
342 | ```
343 | long expectedTimeMillis = 123;
344 | String expectedText = "Let's count to three."
345 | VideoSubtitle expectedSubtitle =
346 |         new VideoSubtitle(expectedTimeMillis, expectedText);
347 | 
348 | assertEquals(expectedSubtitle, actualSubtitle);
349 | ```
350 | 
351 | If these values are not equal, then `assertEquals` prints both arguments in the thrown assertion. (Which is only helpful if `toString` is implemented, as described below!)
352 | 
353 | #### Implementing `equals` with inheritance
354 | 
355 | If there is a base class, then the derived class `equals` implementation should call the base class `equals` implementation. For example, consider the abstract base class `ContentItemUserProgress`:
356 | 
357 | ```java
358 | public abstract class ContentItemUserProgress {
359 |     public final ContentItemIdentifier contentItemIdentifier;
360 |     public final UserProgressLevel progressLevel;
361 | 
362 |     @Override
363 |     public boolean equals(Object o) {
364 |         if (this == o) return true;
365 |         if (!(o instanceof ContentItemUserProgress)) return false;
366 | 
367 |         ContentItemUserProgress that = (ContentItemUserProgress) o;
368 | 
369 |         return (contentItemIdentifier.equals(that.contentItemIdentifier) &&
370 |                 progressLevel == that.progressLevel);
371 |     }
372 | }
373 | ```
374 | 
375 | The subclass `VideoUserProgress` tests that the instance fields in the base class are equal before testing that its own instance fields are equal:
376 | 
377 | ```java
378 | public final class VideoUserProgress extends ContentItemUserProgress {
379 |     public final SecondsWatched secondsWatched;
380 |     public final Optional lastWatchedDate;
381 | 
382 |     @Override
383 |     public boolean equals(Object o) {
384 |         if (this == o) return true;
385 |         if (!(o instanceof VideoUserProgress)) return false;
386 | 
387 |         if (!super.equals(o)) return false;
388 | 
389 |         VideoUserProgress that = (VideoUserProgress) o;
390 | 
391 |         return (secondsWatched.equals(that.secondsWatched) &&
392 |                 lastWatchedDate.equals(that.lastWatchedDate));
393 |     }
394 | }
395 | ```
396 | 
397 | #### Implementing `hashCode`
398 | 
399 | The `Objects` method from the `com.google.common.base` package contains a `hashCode` method that computes a hash value for a list of arguments. Use it to compute the hash code of all the instance fields of a class:
400 | 
401 | ```
402 | @Override
403 | public int hashCode() {
404 |     return Objects.hashCode(lastSecondWatched, totalSecondsWatched);
405 | }
406 | ```
407 | 
408 | #### Implementing `hashCode` with inheritance
409 | 
410 | If there is a base class, then the derived class `hashCode` implementation should call the base class `hashCode` implementation. For example, again consider the base class `ContentItemUserProgress`:
411 | 
412 | ```java
413 | public final class VideoUserProgress extends ContentItemUserProgress {
414 |     public final SecondsWatched secondsWatched;
415 |     public final Optional lastWatchedDate;
416 | 
417 |     @Override
418 |     public int hashCode() {
419 |         return Objects.hashCode(contentItemIdentifier, progressLevel);
420 |     }
421 | }
422 | ```
423 | 
424 | The subclass `VideoUserProgress` mixes in the superclass `hashCode` value into the `hashCode` value that it returns:
425 | 
426 | ```java
427 | public final class VideoUserProgress extends ContentItemUserProgress {
428 |     public final SecondsWatched secondsWatched;
429 |     public final Optional lastWatchedDate;
430 | 
431 |     @Override
432 |     public int hashCode() {
433 |         return Objects.hashCode(super.hashCode(), secondsWatched, lastWatchedDate);
434 |     }
435 | }
436 | ```
437 | 
438 | #### Implementing `toString`
439 | 
440 | The `MoreObjects` class from the `com.google.common.base` package has a useful `toStringHelper` method that, as its name implies, helps construct a `toString` value. Again, consider the `SecondsWatched` class:
441 | 
442 | ```java
443 | public class SecondsWatched {
444 |     public final long lastSecondWatched;
445 |     public final long totalSecondsWatched;
446 | 
447 |     @Override
448 |     public String toString() {
449 |         return MoreObjects.toStringHelper(this)
450 |                 .add("lastSecondWatched", lastSecondWatched)
451 |                 .add("totalSecondsWatched", totalSecondsWatched)
452 |                 .toString();
453 |     }
454 | }
455 | ```
456 | 
457 | If `SecondsWatched` is instantiated with a `lastSecondWatched` value of `5` and a `totalSecondsWatched` value of `10`, then invoking its `toString` method will return:
458 | 
459 | ```
460 | SecondsWatched={lastSecondWatched=5, totalSecondsWatched=10}
461 | ```
462 | 
463 | #### Implementing `toString` with inheritance
464 | 
465 | If there is a base class, it may be helpful for it to provide a `protected` factory method that creates a `ToStringHelper` instance and adds to it the base class fields. The derived class implementation of `toString` can then invoke this base class factory method and add to it the derived class fields before returning. For example, again consider the base class `ContentItemUserProgress`:
466 | 
467 | ```java
468 | public abstract class ContentItemUserProgress {
469 |     public final ContentItemIdentifier contentItemIdentifier;
470 |     public final UserProgressLevel progressLevel;
471 | 
472 |     protected MoreObjects.ToStringHelper getToStringHelper() {
473 |         return MoreObjects.toStringHelper(this)
474 |                 .add("contentItemIdentifier", contentItemIdentifier)
475 |                 .add("kind", getItemKind())
476 |                 .add("progressLevel", progressLevel);
477 |     }
478 | }
479 | ```
480 | 
481 | The subclass `VideoUserProgress` then adds its own fields to the `ToStringHelper` before returning:
482 | 
483 | ```java
484 | public final class VideoUserProgress extends ContentItemUserProgress {
485 |     public final SecondsWatched secondsWatched;
486 |     public final Optional lastWatchedDate;
487 | 
488 |     @Override
489 |     public String toString() {
490 |         return getToStringHelper()
491 |                 .add("secondsWatched", secondsWatched)
492 |                 .add("lastWatchedDate", lastWatchedDate)
493 |                 .toString();
494 |     }
495 | }
496 | ```
497 | 
498 | ### Immutable Collections
499 | 
500 | As described earlier, immutability is a critical aspect of controlling complexity in our programs. As such, for each of the collection interfaces `List`, `Map`, `SortedMap`, `Set`, and `SortedSet`, Guava defines an implementation whose instances are immutable. This is only possible because the mutating methods of each collection interface, such as `add`, `set`, or `remove`, are defined as optional operations. The underlying implementation can choose to implement the method as specified by the interface, or throw an `UnsupportedOperationException`. The collections defined by Guava choose the latter.
501 | 
502 | > The standard libraries for some languages, such as Objective-C and Scala, instead define separate types for mutable and immutable collections.
503 | 
504 | #### Construction from individual elements
505 | 
506 | To construct an immutable collection from individual elements, invoke the correct overload form of its `of` static factory method:
507 | 
508 | ```java
509 | public static final List ALL_COLUMNS = ImmutableList.of(
510 |     CONTENT_KEY,
511 |     Videos.VIDEO_SIZE,
512 |     Videos.VIDEO_STATUS,
513 |     Videos.TRANSCRIPT_SIZE,
514 |     Videos.TRANSCRIPT_STATUS
515 | );
516 | ```
517 | 
518 | #### Construction from another collection
519 | 
520 | To construct an immutbale collection with the contents of an collection, such as an `Iterable` or an array, call the correct overload of its `copyOf` static factory method:
521 | 
522 | ```java
523 | public final class NodeTree {
524 |   public final List nodes;
525 |   public final Set relationships;
526 | 
527 |   public NodeTree(final List nodes, final Set relationships) {
528 |     this.nodes = ImmutableList.copyOf(nodes);
529 |     this.relationships = ImmutableSet.copyOf(relationships);
530 |   }
531 | 
532 |   ...
533 | }
534 | ```
535 | 
536 | #### Construction with a builder
537 | 
538 | Finally, if you cannot statically construct such an immutable instance, use an instance of its corresponding [builder](https://en.wikipedia.org/wiki/Builder_pattern) class. Such an instance is mutable and accumulates elements. Calling `build` constructs an immutable instance with those accumulated elements:
539 | 
540 | ```java
541 | public static List readSubtitles(JsonReader reader) throws IOException {
542 |   ImmutableList.Builder builder = ImmutableList.builder();
543 | 
544 |   reader.beginArray();
545 |   while (reader.hasNext()) {
546 |     builder.add(VideoSubtitleJsonDecoder.read(reader));
547 |   }
548 |   reader.endArray();
549 | 
550 |   return builder.build();
551 | }
552 | ```
553 | 
554 | #### Defensive copying
555 | 
556 | A class should defensively copy any collection instance that it is injected with. For example, consider the `JavaScriptCommand` class:
557 | 
558 | ```java
559 | public final class JavaScriptCommand {
560 |   public final String methodName;
561 |   public final List parameters;
562 | 
563 |   public JavaScriptCommand(String methodName, List parameters) {
564 |     this.methodName = Preconditions.checkNotNull(methodName);
565 |     this.parameters = ImmutableList.copyOf(parameters);
566 |   }
567 | 
568 |   ...
569 | }
570 | ```
571 | 
572 | If a client constructs a `JavaScriptCommand` instance, and then mutates the `List` instance that it passed in as the `parameters` value, then the `JavaScriptCommand` instance will not reflect those mutations. By defensively copying, it enforces its immutability.
573 | 
574 | Note that the `copyOf` method above will use reflection to test whether its parameter is also an `ImmutableList` instance. If so, then it simply returns its parameter instead of constructing a new `ImmutableList` instance. This is because we must only make defensive copies to guard against unexpected mutations, but immutable instances by definition do not afford that.
575 | 
576 | Consequently, the following test will pass:
577 | 
578 | ```java
579 | List original = ImmutableList.of("foo", "bar");
580 | List copy = ImmutableList.copyOf(original);
581 | 
582 | assertSame(original, copy);
583 | assertTrue(original == copy);
584 | ```
585 | 
586 | #### Guarding aginst `null`
587 | 
588 | Finally, `ImmutableList` and `ImmutableSet` prohibit `null` elements, while `ImmutableMap` prohibits `null` keys or values. Attempting to construct such an instance will throw a `NullPointerException`. If you require an `ImmutableMap` that permits `null` values, we have an `ImmutableNullableMap` instance. But before building a `List` or `Set` analogue, thoroughly consider alternative designs.
589 | 
590 | ### Using `Optional`
591 | 
592 | We have seen how `checkNotNull` ensures that instances are not mistakenly constructed with `null` values. But if a parameter value or a return value belonging to a method signature can be `null`, then we precede its type with the `@Nullable` annotation. For example:
593 | 
594 | ```java
595 | public static @Nullable URI toUri(final @Nullable String value) throws URISyntaxException {
596 |   return (value != null) ? new URI(value) : null;
597 | }
598 | ```
599 | 
600 | We can even annotate variable declarations:
601 | 
602 | ```java
603 | @Nullable URI downloadUrl = toUri(downloadUrlString);
604 | ```
605 | 
606 | In more modern languages, *nullability* is encoded by the type system. In Swift, for example, a type suffixed with `?` can assume `null`, while a type that stands alone cannot:
607 | 
608 | ```swift
609 | let x: String = "foo"
610 | let y: String? = null
611 | 
612 | let z: String = null  // compilation error
613 | ```
614 | 
615 | In Java, The `Optional` class from Guava is a library-level imitation of this concept. It is not as robust and so it is not a substitute. But nonetheless it succeeds in forcing us to account for `null` values at compile-time.
616 | 
617 | For example, consider an `toIso8601` method that converts a `Date` parameter to a string in ISO 8601 format. It expects that its `Date` parameter is not `null`, and even uses `Preconditions.checkNotNull` to assert this.
618 | 
619 | A client may store the date at which a video was last watched by the user. It could convert the corresponding `Date` instance to ISO 8601 like so:
620 | 
621 | ```java
622 | Date lastWatchedDate = ...
623 | String lastWatchedIso8601 = toIso8601(lastWatchedDate);
624 | ```
625 | 
626 | But this does not capture that `lastWatchedDate` can be `null` if the user has never watched the corresponding video before. Consequently, `toIso8601` will be invoked with a `null` parameter, which in turn will cause its `Preconditions.checkNotNull` statement to throw a `NullPointerException` at runtime.
627 | 
628 | By representing `lastWatchedDate` as an `Optional`, we can force accounting for the nullability of `lastWatchedDate` at compile-time. The client must explicitly test for the presence of a contained `Date` value before extracting it from the optional and passing it to the `toIso8601` method:
629 | 
630 | ```java
631 | Optional lastWatchedDate = ...
632 | @Nullable String lastWatchedString = lastWatchedDate.isPresent()
633 |     ? toIso8601(lastWatchedDate.get())
634 |     : null;
635 | ```
636 | 
637 | ### Using `Predicates` and `Functions`
638 | 
639 | TODO
640 | 
641 | ### Using `Lists` and `Maps`
642 | 
643 | TODO
644 | 
645 | ### Using `FluentIterable`
646 | 
647 | TODO
648 | 
649 | 


--------------------------------------------------------------------------------
/style/go.md:
--------------------------------------------------------------------------------
  1 | # Go
  2 | 
  3 | Our style guide is based on the advice in [Effective
  4 | Go](https://golang.org/doc/effective_go.html) and the [Code Review
  5 | Comments wiki](https://github.com/golang/go/wiki/CodeReviewComments),
  6 | with the following additions and modifications.
  7 | 
  8 | ## Naming
  9 | 
 10 | ### Module names with multiple words should use snake_case
 11 | 
 12 | According to "Effective Go," we should use short package names, that
 13 | are a single word.  For our library code under pkg/, we follow that
 14 | recommendation.
 15 | 
 16 | But in our services/ tree, where our packages are all internal, we
 17 | have a little bit more freedom (and a lot more packages to name). In
 18 | some cases multi-word package names are clearer/less ambiguous, and in
 19 | those cases, separate the words with underscores.
 20 | 
 21 | ### Use a leading underscore for file-private symbols
 22 | 
 23 | In addition to the standard Go convention that capitalized names are
 24 | public and lowercased names are visible to all files in the same
 25 | package, we add an additional rule: if you want to declare that only
 26 | _this_ file should access the symbol, name it with a leading
 27 | underscore.
 28 | ```go
 29 | // style/visibility.go
 30 | package style
 31 | func AnyoneCanCall()                {}
 32 | func anyFileInPackageStyleCanCall() {}
 33 | func _visibilityDotGoCanCall()      {}
 34 | ```
 35 | 
 36 | The same convention applies to type names and global
 37 | variables/constants.  For struct fields and method names, an
 38 | underscore is a hint that the name is somehow private even within the
 39 | package, but this is not enforced.
 40 | 
 41 | Note that we allow tests in the same package to access file-private
 42 | symbols, but tests in different packages must follow the rules and
 43 | only access exported symbols.
 44 | 
 45 | The reason for this rule is to help code readers understand the scope
 46 | of code as they're reading it.  It's very common to write helper
 47 | functions that are only used once -- maybe twice -- and by another
 48 | function in the same file.  Marking those helper functions tells
 49 | people reading the code not to try to make sense of an awkward API, or
 50 | generically named function, or lacking documentation: looking at the
 51 | nearby caller would be more productive instead.
 52 | 
 53 | ### Initialisms
 54 | 
 55 | Go
 56 | [chooses](https://github.com/golang/go/wiki/CodeReviewComments#initialisms)
 57 | naming like `RequestURL`, rather than `RequestUrl`, for initialisms
 58 | like `URL`.  (Prefixes like `urlPath` are not capitalized at all.)  We
 59 | follow this but not religiously; if multiple initialisms appear
 60 | consecutively (`NWEAMAPID`), do what seems clearest in context.
 61 | 
 62 | 
 63 | ## Formatting
 64 | 
 65 | Most issues of formatting are covered by gofmt -- we actually use
 66 | [gofumpt](https://github.com/mvdan/gofumpt) -- but we add a few
 67 | additional rules.
 68 | 
 69 | ### Line length
 70 | 
 71 | Neither Go nor gofmt specify a maximum line length.  We do: most lines
 72 | should be at most 79 characters, and all lines must be at most 100
 73 | characters.
 74 | 
 75 | Specifically, code should be wrapped around 79 characters, but a few
 76 | over is okay if there's not a great way to wrap the line.  Comments
 77 | must always be wrapped at 79, unless they have non-breaking words like
 78 | urls, that are longer.
 79 | 
 80 | Go is liberal in allowing line breaks without explicit continuation.
 81 | Any binary operator that ends a line signals that the next line
 82 | continues the same expression.  For example:
 83 | ```go
 84 | // bad
 85 | if myLongCondition("isToo", long) && yourEvenLongerCondition("has", "so", "many", "arguments") {
 86 |     …
 87 | }
 88 | 
 89 | // good
 90 | if myLongCondition("isToo", long) &&
 91 |     yourEvenLongerCondition("has", "so", "many", "arguments") {
 92 |     …
 93 | }
 94 | ```
 95 | 
 96 | In general, this style is preferable to breaking up a single element
 97 | of the condition.  When possible, break in a way that matches the
 98 | precedence of the operators:
 99 | ```go
100 | // bad
101 | if aa && ab && ac || ba &&
102 |     bb && bc {
103 |     …
104 | }
105 | 
106 | // good
107 | if aa && ab && ac ||
108 |     ba && bb && bc {
109 | ...
110 | }
111 | 
112 | // ok
113 | if aa &&
114 |     ab &&
115 |     ac ||
116 |     ba &&
117 |        bb &&
118 |        bc {
119 |     ...
120 | }
121 | ```
122 | As you can see, gofmt's indentation will help you out in some of the
123 | awkward cases.  Similar style applies to other operators like `+`, and
124 | even the field/method-lookup operator `.`. (Of course in reality, this
125 | code would benefit from some parentheses, which will also help you get
126 | the wrapping right.)
127 | 
128 | For function/method definitions, if the signature is too long for a
129 | single line, put each argument on its own line (note you will need a
130 | trailing comma):
131 | ```go
132 | // bad
133 | func (t *MyType) MyBadMethod(ctx context.Context, argumentOne string, argumentTwo string) (string, error) {
134 |     ...
135 | }
136 | 
137 | func (t *MyType) MyBadMethod(
138 |     ctx context.Context, argumentOne string, argumentTwo string,
139 | ) (string, error) {
140 |     ...
141 | }
142 | 
143 | // good
144 | func (t *MyType) MyGoodMethod(
145 |     ctx context.Context,
146 |     argumentOne string,
147 |     argumentTwo string,
148 | ) (string, error) {
149 |     ...
150 | }
151 | 
152 | func (t *MyType) MyOtherGoodMethod(
153 |     ctx context.Context,
154 |     argumentOne, argumentTwo string,
155 | ) (string, error) {
156 |     ...
157 | }
158 | ```
159 | It is acceptable to put multiple arguments on the same line if they
160 | use the `nameOne, nameTwo type` style, but otherwise either the
161 | signature should be a single line, or each argument should have its
162 | own line.  The same wrapping is possible, albeit rarely necessary, for
163 | receivers and returns:
164 | ```go
165 | func (
166 |     t *MyVeryLongReceiverTypeName,
167 | ) MyVeryLongMethodName(
168 |     ctx context.Context,
169 | ) (
170 |     MyVeryLongReturnTypeName,
171 |     MyOtherVeryLongReturnTypeName,
172 | ) {
173 |     ...
174 | }
175 | ```
176 | 
177 | Sometimes, the best way is a temporary variable:
178 | ```go
179 | // bad
180 | donationAsk.DefaultDonationFrequency = donationFrequencyGraphQLtoModel[*input.DefaultDonationFrequency]
181 | 
182 | // good
183 | freq := *input.DefaultDonationFrequency
184 | donationAsk.DefaultDonationFrequency = donationFrequencyGraphQLtoModel[freq]
185 | ```
186 | 
187 | A few lines get exceptions to even the 100 character rule, because
188 | there's no good way to wrap them.  These include machine-readable
189 | comments (like //go:generate), lines ending with a URL, or lines
190 | containing struct tags.
191 | ```go
192 | // ok
193 | var serviceURL = "https://www.my.long.service.domain.name/some/path/to/api/v1/my/call/yikes/"
194 | 
195 | type myStruct struct {
196 |     MyLongFieldName map[MyLongFieldKeyType]MyLongFieldValueType `json:"myLongFieldName" datastore:"my_long_field_name"`
197 | }
198 | 
199 | //go:generate go run github.com/Khan/mypackage/path/to/codegen arguments --long-path=/path/to/my/directory
200 | ```
201 | 
202 | ### Leave a blank line between toplevel functions
203 | 
204 | This is one detail gofmt doesn't specify.  We choose to leave a blank
205 | line before and after each toplevel function.  Other toplevel
206 | declarations, like `var`, `const`, and `type`, may go on consecutive
207 | lines to each other, especially if they are related and fit on a
208 | single line.
209 | 
210 | ```go
211 | // good
212 | type fooString string
213 | type barString string
214 | 
215 | type bazString string
216 | var baz bazString
217 | 
218 | var host = "www.khanacademy.org"
219 | var hostOverride string
220 | 
221 | func DoSomething() {
222 |     ...
223 | }
224 | 
225 | func somethingElse() {
226 |     ...
227 | }
228 | 
229 | // ok
230 | type fooString string
231 | var unrelated = 2
232 | 
233 | type fooInnerStruct {
234 |     bar string
235 |     baz int
236 | }
237 | type fooOuterStruct {
238 |     fooInnerStruct
239 |     qux map[string]string
240 | }
241 | 
242 | // bad
243 | type notLikeThis string
244 | func Yuck() {
245 |     ...
246 | }
247 | func yuckier() {
248 |     ...
249 | }
250 | var dontDoThis string
251 | ```
252 | 
253 | 
254 | ## Documentation
255 | 
256 | The advice in [Effective
257 | Go](https://golang.org/doc/effective_go.html#commentary) applies here
258 | too.  For all godoc-based documentation, it can be useful to check how
259 | it renders in godoc on the commandline (`go doc -all ./my/pkg`) or in
260 | a browser (`godoc -http=localhost:6060`).
261 | 
262 | ### Documenting packages and files
263 | 
264 | Packages may be documented with a README.md, or a godoc package
265 | comment.  Prefer godoc if the package's contents and consumers are all
266 | Go code (such as `pkg/mypackage` or `services/my-service/testutil`)
267 | and README if not (such as `services/my-service` or
268 | `services/my-service/my-data-files`).  The formatting in godoc is not
269 | as expressive as markdown, so packages where complex formatting is
270 | particularly useful to the documentation may wish to have a godoc and
271 | a README, which reference each other.
272 | 
273 | Package comments may be at the top of any Go file, before the `package
274 | mypackage`.  Typically, they should go in the main entrypoint (often
275 | called `mypackage.go`, or sometimes `api.go` or `client.go`).
276 | Particularly long package comments can go in their own file,
277 | canonically `doc.go`.  Only one file should have a package comment (Go
278 | doesn't require this, but it's a bit confusing otherwise.)
279 | 
280 | Package comments or READMEs should include a general description of
281 | the package for someone unfamiliar with it, and general pointers as to
282 | how to use it.  For example, they may point to the most common
283 | entrypoint functions or types, or give a usage example.  They may also
284 | include any other useful documentation that doesn't pertain to a
285 | specific type or function.  Package comments may include
286 | section-headings, which are simply text on a line by itself with no
287 | punctuation.
288 | 
289 | Go has no convention for file-level documentation.  We choose to put
290 | such documentation after the package comment, before the imports.
291 | This documentation should contextualize this file within the package,
292 | and is intended for other implementers (or people trying to understand
293 | the code) moreso than for the package's consumers.  All non-test files
294 | in a package should have a file comment, unless the package is only a
295 | single (non-test) file.
296 | 
297 | ### Documenting types, functions, methods, and fields
298 | 
299 | As Effective Go says, all exported names (types, functions, methods,
300 | fields, etc.) should have godoc comments.  Such comments start with a
301 | summary, which begins "FunctionName gets/does/returns/etc. …" and uses
302 | full sentences to give a short (1-2 line) summary of the function.  If
303 | more information is useful, leave a blank comment-line, then further
304 | comments.  Doc-comments need not repeat the signature of the function
305 | (or type of the field), except as to document arguments or returns not
306 | obvious from the name and type.
307 | 
308 | Use [named
309 | returns](https://golang.org/doc/effective_go.html#named-results) if
310 | the types are not sufficient to tell what the return values mean; this
311 | is especially useful if multiple of them have the same type:
312 | ```go
313 | // bad
314 | func GetEmailBody(...) (string, string, error) { … }
315 | 
316 | // good
317 | func GetEmailBody(...) (text, html string, err error) { … }
318 | ```
319 | 
320 | Methods which are exclusively used via an interface (such as exported
321 | methods of unexported types) should be documented, but the
322 | documentation may simply refer to the interface, e.g. "MyMethod
323 | implements the interface MyInterface".  If the method may also be used
324 | on its own, or there is more to add about this type's particular
325 | implementation of the interface, that can be included as well.
326 | 
327 | Unexported names should often be documented, too, for other
328 | implementers of the package.  You can see the documentation with `go
329 | doc -u`, or by reading the file.
330 | 
331 | 
332 | ## Imports
333 | 
334 | ### Always qualify imports, with their package name if possible
335 | 
336 | Go has three styles of import: you can import a package with its
337 | default name (the last component of its path), with your own name, or
338 | unqualified (by using the special name ".").  Whenever possible, use
339 | the default name; this makes it easier for readers to know what code
340 | is referenced without reading your import block.  If this name is not
341 | acceptable (e.g. it's very long, not meaningful, not a valid
342 | identifier, or collides with another name), it's okay to use an
343 | abbreviated name, but don't abbreviate so far that the name is
344 | nonspecific.  (If the package is first-party, a better name may be in
345 | order!)  Do not import unqualified.  For example:
346 | ```go
347 | import (
348 |     // good
349 |     "net/http"
350 |     "cloud.google.com/go/datastore"
351 |     "github.com/Khan/webapp/pkg/lib"
352 |     cloudkms "cloud.google.com/go/kms/apiv1"
353 |     userlib "github.com/Khan/webapp/pkg/user"
354 |     mobileData "github.com/Khan/webapp/services/mobile-data"
355 | 
356 |     // ok only if there are naming collisions or
357 |     // other problems with "lib"
358 |     khanPkgLib "github.com/Khan/webapp/pkg/lib"
359 | 
360 |     // bad
361 |     l "github.com/Khan/webapp/pkg/lib" // nonspecific
362 |     . "github.com/Khan/webapp/pkg/lib" // unqualified
363 | )
364 | ```
365 | 
366 | ### Sort imports into stdlib, first-party, and third-party
367 | 
368 | Standard go style requires that all imports use a single import
369 | statement, but allows blank lines to separate groups of imports within
370 | that.  We follow a style similar to python: standard library imports,
371 | third-party imports, and first-party imports go in separate blocks.
372 | We consider "pkg" imports from webapp to be first-party imports.  Each
373 | block is sorted (goimports enforces this).  For example:
374 | ```go
375 | // good
376 | import (
377 |     "log"
378 |     "net/http"
379 |     "os"
380 | 
381 |     "github.com/99designs/gqlgen/handler"
382 | 
383 |     "github.com/Khan/webapp/pkg/lib"
384 |     "github.com/Khan/webapp/pkg/web"
385 |     "github.com/Khan/webapp/services/myservice"
386 |     "github.com/Khan/webapp/services/myservice/mypkg"
387 | )
388 | 
389 | // bad
390 | import (
391 |     "github.com/99designs/gqlgen/handler"
392 |     "github.com/Khan/webapp/pkg/lib"
393 | 
394 |     "github.com/Khan/webapp/pkg/web"
395 |     "github.com/Khan/webapp/services/myservice"
396 |     "github.com/Khan/webapp/services/myservice/mypkg"
397 |     "log"
398 | 
399 |     "net/http"
400 | )
401 | ```
402 | 
403 | 
404 | ## Best practices
405 | 
406 | ### Be sparing in using assignments in if statements
407 | 
408 | Go lets you do -- perhaps encourages you to do -- code like this:
409 | ```go
410 | // bad
411 | if value, err := myfunc(); err != nil { ... }
412 | ```
413 | This hides the important part -- calling `myfunc()` and assigning its
414 | return-type to a new local variable -- in the middle of the line, with
415 | lots of other stuff going on in that line as well.
416 | 
417 | Clearer is to do the assignment separately, even though it's an extra
418 | line of code:
419 | ```go
420 | // good
421 | value, err := myfunc()
422 | if err != nil { ... }
423 | ```
424 | 
425 | ### Do not use unadorned returns
426 | 
427 | If you use [named
428 | returns](https://golang.org/doc/effective_go.html#named-results) for a
429 | function, Go allows you to just say `return` and it will automatically
430 | return the named variables.  Opinions differ about whether this helps
431 | or hurts readability.  We follow the advice on the
432 | [wiki](https://github.com/golang/go/wiki/CodeReviewComments#named-result-parameters):
433 | say `return , ` as if the return values were not named,
434 | unless the function is very short.
435 | 
436 | ### Construct URLs using net/url, not string methods
437 | 
438 | In general, avoid using string methods to manipulate URLs, such as by
439 | making a relative URL absolute: it's a bug-magnet as an extra or
440 | missing slash can totally break the URL.  Instead, parse the URLs
441 | using `net/url.Parse`, and manipulate the `net/url.URL` objects.  This
442 | can be a bit more verbose but it's much safer.
443 | 
444 | The same applies for file paths: use `path/filepath`, not string
445 | manipulation.
446 | 
447 | For example:
448 | ```go
449 | // bad
450 | return "https://" + req.Host + "/about"
451 | 
452 | // good
453 | aboutPageURL := url.URL{
454 |     Scheme: "https",
455 |     Host: req.Host,
456 |     Path: "/about",
457 | }
458 | return url.String()
459 | ```
460 | 
461 | ### Use reflection sparingly, especially in application code
462 | 
463 | Go's reflect library is useful and powerful, but it makes for much
464 | harder-to-read and less type-safe code.  We do sometimes need it,
465 | especially in infrastructure code, but it's best to avoid if it's not
466 | really necessary.  Definitely don't use reflect if all you need is a
467 | type switch!
468 | 
469 | ### Do not be afraid to use codegen
470 | 
471 | It is a great way to get type-safety, at least until generics come along.
472 | 
473 | 
474 | ## Concurrency
475 | 
476 | Go makes writing good concurrent code easier than some languages, but
477 | there are still some rough edges and style rules to be aware of.
478 | 
479 | ### Use goroutines when *you* have concurrent work to do
480 | 
481 | In some languages, it's common to write functions which return a
482 | Promise (or similar), to allow the caller to wait on the result.  In
483 | Go, there is no need: there is no "blocking the event loop" to worry
484 | about, and if the caller wants to do something else while they wait,
485 | they can simply use their own goroutine.  So all functions should
486 | typically be written to simply return their result, not a
487 | promise-style structure.
488 | 
489 | For more on this topic, see [this
490 | talk](https://drive.google.com/file/d/1nPdvhB0PutEJzdCq5ms6UI58dp50fcAN/view).
491 | ```go
492 | // good: doesn't use a goroutine
493 | func GetUserData(ctx ...) (*UserData, error) {
494 |     err := ctx.Datastore().Get(...)
495 |     return userData, err
496 | }
497 | 
498 | // good: uses goroutines to do two things in parallel
499 | func GetUserSettingsAndUserData(ctx ...) (*UserData, *UserSettings, error) {
500 |     g, ctx := errgroup.WithContext(ctx)
501 |     g.Go(func() error {
502 |         userData, err = GetUserData(ctx)
503 |         return err
504 |     })
505 |     g.Go(func() error {
506 |         userSettings, err = GetUserSettings(ctx)
507 |         return err
508 |     })
509 |     err := g.Wait()
510 |     return userData, userSettings, err
511 | }
512 | 
513 | // bad: forces concurrency onto its caller
514 | func GetUserData(ctx ...) (<-chan *UserData, error) {
515 |     ...
516 | }
517 | ```
518 | 
519 | > [Khan-specific: Instead of ErrGroup or -- gasp! -- WaitGroup,
520 | > use `pkg/external/opentelemetry/tracegroup`.  Its API is
521 | > similar to ErrGroup but it takes care of promoting the context
522 | > for you, and also automatically sends traces for each goroutine.]
523 | 
524 | ### Arrange for all your goroutines to exit
525 | 
526 | If you start a goroutine, it's your responsibility to arrange for it
527 | to exit, when this request ends or otherwise, unless it's really
528 | intended to go forever.
529 | 
530 | The easiest, and recommended, way to do this for most users is with
531 | `x/sync/errgroup`.  This package makes it easy to start a bunch of
532 | pieces of work, wait for them all to complete, and early-exit if any
533 | fail.  Make sure to use `errgroup.WithContext` to set up the errgroup,
534 | and pass the returned context into each goroutine.
535 | 
536 | Generally, make sure to always pass a context through to your callees.
537 | This helps ensure that if a request is cancelled, all its work will
538 | quickly exit.  If you're doing something that might take a while, make
539 | sure you check for context-cancellation.  Typically the low-level APIs
540 | will do that for you, so you just need to pass them a context, but if
541 | you are doing something slow that doesn't handle context, you'll need
542 | to do so yourself, typically with a `select` statement.
543 | 
544 | To explicitly set a timeout on some work (in a goroutine or not), use
545 | `context.WithTimeout` or `context.WithDeadline` to set a deadline on
546 | the context which will be used for that work; then follow the
547 | instructions in the previous paragraph to ensure that deadline is
548 | observed.  See their documentation for more.
549 | 
550 | > [Khan-specific: For work that may outlive the request (such as
551 | > "fire-and-forget" RPCs), use `pkg/kacontext.Detach` along with a
552 | > goroutine; see its documentation for details.  Note that such work is
553 | > not guaranteed to happen, for example if the instance is no longer
554 | > needed; use tasks for larger or more important blocks of asynchronous
555 | > work.]
556 | 
557 | ### Handle panics inside goroutines
558 | 
559 | When starting a goroutine, make sure you call a defer that handles any
560 | panics, before doing anything else.  This ensures that a a panic in
561 | your goroutine will fail just this request, and not the whole
562 | webserver.
563 | 
564 | > [Khan-specific: use `defer log.PanicHandler(ctx.Log())` for this.]
565 | 
566 | ### If in doubt, use a lock
567 | 
568 | If you enjoy thinking about concurrency, you'll find the Go
569 | specification as when it's safe to read and write to shared memory
570 | very interesting.  In general, avoid using this knowledge: if you have
571 | to think carefully to figure out whether you need a lock to share
572 | memory safely, you probably need a lock.
573 | 
574 | ### You might not need channels
575 | 
576 | Channels are a great tool, and are often useful for returning results
577 | back from work happening in a goroutine.  However, using channels
578 | means paying attention to when they might block, and making sure to
579 | close them if needed.  Not all concurrent code needs channels.
580 | ```go
581 | // good: needs channels to do a select
582 | c := make(chan int)
583 | go func{
584 |     result := ... // some work that can't be interrupted
585 |     c <- result
586 |     close(c)
587 | }()
588 | select {
589 |     case <-ctx.Done():
590 |         return "", ctx.Err() // cancelled or timed out
591 |     case val := <-c:
592 |         return val // operation completed
593 | }
594 | 
595 | // good: doesn't need channels
596 | results := make([]int, len(inputs))
597 | g, ctx := errgroup.WithContext(ctx)
598 | for i, input := range inputs {
599 |     g.Go(func() error {
600 |         results[i] = f(input)
601 |         return nil
602 |     })
603 | }
604 | err := g.Wait()
605 | return results, err
606 | 
607 | // bad: uses channels unnecessarily, which leads to several bugs!
608 | c := make(chan int) // unbuffered channel
609 | g, ctx := errgroup.WithContext(ctx)
610 | for i, input := range inputs {
611 |     g.Go(func() error {
612 |         c <- f(input) // waits until receive (range c below)
613 |         return nil
614 |     })
615 | }
616 | err := g.Wait() // waits until goroutines finish -- DEADLOCK
617 | var results []int
618 | for val := range c { // waits until channel is closed (it never is)
619 |     results = append(results, val)
620 | }
621 | return results, err
622 | ```
623 | 
624 | ## Contexts
625 | 
626 | > [Khan-specific: Note that most Khan Academy code uses the enriched
627 | > KAContext system described by ADR-229 rather than ordinary Go
628 | > context; see pkg/kacontext for further documentation.  The below
629 | > rules apply to both Go-style context and KA-style context.]
630 | 
631 | ### Context should be named `ctx` and the first argument
632 | 
633 | If a function needs to be passed a `context.Context`, that context
634 | should always be the first argument and should be named `ctx`.
635 | Variables referring to context should generally be named `ctx`.
636 | 
637 | > [Khan-specific: if the code needs to distinguish between Go-context
638 | > and KA-context, such as the caller of `kacontext.Upgrade`, it may use
639 | > `ktx` for the KA-context.]
640 | 
641 | ### Only use `context.Background` in special circumstances
642 | 
643 | It's easy to use `context.Background` because you don't have to pass
644 | anything around.  But unless you're spawning something that you don't
645 | want canceled if the current request is canceled, like a long-lived
646 | thread, it's the wrong thing to use.  Pass around an actual context
647 | object instead.
648 | 
649 | This rule does not apply to tests, nor to `main` or `init` functions,
650 | where you aren't necessarily within a request or any other meaningful
651 | context.
652 | 
653 | ### Do not store context in a struct
654 | 
655 | The package documentation says:
656 | 
657 | > Do not store Contexts inside a struct type; instead, pass a Context
658 | > explicitly to each function that needs it.
659 | 
660 | Other than a few special cases in library code where there is no good
661 | alternative, it's inadvisable to store context in a struct: the caller
662 | may need to modify that context, which gets to be a mess as the struct
663 | gets nested.  Instead, pass the context explicitly.
664 | 
665 | ## Google libs
666 | 
667 | ### Low-level functions that modify datastore should take a Transaction object or Client object
668 | 
669 | If a low-level function -- one not immediately called by an API
670 | handler or graphql resolver -- needs to `put()` to the datastore, it
671 | should explicitly take in a `datastore.Transaction` object, if the
672 | `put()` needs to be transactional, or a `ctx` that includes
673 | `datastore.KAContext`, if it does not.  (A `put()` needs to be
674 | transactional if two things are being put in the same function, and we
675 | must have both-or-neither semantics; or if the helper function does
676 | get()-modify-put().)  This is how the function documents whether it
677 | needs to take place in a transaction or not.
678 | 
679 | ### Do not use get-or-insert semantics for read-only functions
680 | 
681 | The Python datastore library has a `get_or_insert()` function, which
682 | given a key either returns an existing item from the datastore, or
683 | creates a new one if the key is not found.  Do not use that idiom for
684 | code that is semantically read-only -- that is, for code that doesn't
685 | promise that the key exists in the datastore after it exits.
686 | (Accessors, such as `getFoo()`, fall into this category.)  Instead
687 | just return a default entity on key-miss without actually inserting it
688 | into the datastore.
689 | 
690 | ### Return a NotFound error on datastore lookup failures, rather than nil
691 | 
692 | Treat not-found as an error, not as an "expected" case that returns a
693 | nil pointer.  This way, downstream clients don't have to check for
694 | nil-ness in addition to checking for errors (but can still check
695 | separately for not-found vs other errors if they care to).
696 | 
697 | Good:
698 | ```go
699 | func GetMyModel(key *datastore.Key) (*MyModel, error) {
700 |     var mymodel MyModel
701 |     err := ctx.Datastore().Get(ctx, key, &mymodel)
702 |     return &mymodel, err
703 | }
704 | ```
705 | 
706 | Bad:
707 | ```go
708 | func GetMyModel(key *datastore.Key) (*MyModel, error) {
709 |     var mymodel MyModel
710 |     err := ctx.Datastore().Get(ctx, key, &mymodel)
711 |     if errors.Is(err, datastore.EntityNotFound) {
712 |         return nil, nil
713 |     }
714 |     return &mymodel, err
715 | }
716 | ```
717 | 
718 | ## Testing
719 | 
720 | > [Khan-specific: this entire section is Khan-specific]
721 | 
722 | ### Use the Khan Suite instead of Testify's
723 | 
724 | Our tests should always use `servicetest.Suite` (or, for low-level
725 | tests, `khantest.Suite`) rather than Testify's version.  We use suites
726 | to support tear-down functionality, extra methods, and for
727 | consistency; see ADR-222 for more..  The API is more or less the same;
728 | see their respective godocs for details.  The receiver variable should
729 | always be named `suite`, e.g.
730 | ```go
731 | func (suite *mySuite) TestFoo() { … }
732 | ```
733 | 
734 | A file may contain a single suite, or multiple suites if additional
735 | grouping is useful.  The suite type should come first, followed by the
736 | methods, then the runner-test.  If there are multiple suites, they
737 | should come one after the other, and not be interleaved; this makes it
738 | easy to see what code goes with what.
739 | ```go
740 | // good
741 | type mySuite struct{ servicetest.Suite }
742 | // methods of mySuite
743 | // runner-test for mySuite
744 | 
745 | type mySuiteWithField struct {
746 |     servicetest.Suite
747 |     myVar int
748 | }
749 | // methods of mySuiteWithField
750 | // runner-test for mySuiteWithField
751 | ```
752 | 
753 | Suites may override testify lifecycle methods; if they do so those
754 | methods must call the "super", i.e. suite.Suite.MethodName().
755 | 
756 | ### Generally, use require over assert
757 | 
758 | The default style in Testify is for assertions to allow the test to
759 | continue running:
760 | ```go
761 | suite.Assert().Equal(3, 1 + 1)    // or assert.Equal
762 | suite.Assert().Equal(4, 2 + 3)
763 | ```
764 | will report two errors in the same test.  To exit the test if the
765 | assertion fails, one can use require:
766 | ```go
767 | suite.Require().Equal(3, 1 + 1)   // or require.Equal
768 | suite.Require().Equal(4, 2 + 3)   // will not run
769 | ```
770 | We use the latter style: it tends to give clearer errors.  However, we
771 | allow one exception: within a call to `dev/khantest`'s `suite.All`,
772 | use `Assert()` -- this allows reporting multiple error messages which
773 | can aid in debugging.  (See its documentation for details.)  Do not
774 | use `suite.Equal`: always use the equivalent and more explicit
775 | `suite.Assert().Equal`.  (One exception: `suite.FailNow(message)` is
776 | acceptable.)
777 | ```go
778 | // good
779 | suite.Require().Equal(3, 1 + 2)
780 | suite.All(
781 |     suite.Assert().Equal(http.StatusOK, responseCode),
782 |     suite.Assert().Equal("pong\n", responseText))
783 | if badStuffHappened {
784 |     suite.FailNow("yikes, bad stuff happened!")
785 | }
786 | 
787 | // bad
788 | suite.Assert().Equal(3, 1 + 2)
789 | suite.Equal(3, 1 + 2)
790 | suite.All(
791 |     suite.Equal(http.StatusOK, responseCode),
792 |     suite.Equal("pong\n", responseText))
793 | suite.All(
794 |     suite.Require().Equal(http.StatusOK, responseCode),
795 |     suite.Require().Equal("pong\n", responseText))
796 | ```
797 | 
798 | ### Table-driven tests
799 | 
800 | In cases where we have many test cases that all look very similar --
801 | maybe we want to test a simple pure function and we have many
802 | different inputs to test it on -- a table-driven test is often a good
803 | option.  Testify's `suite.Run` is useful for this: it makes each
804 | sub-case execute as a separate Go test, so failures will be reported
805 | individually.  Make sure to give each one a useful name.  For example:
806 | ```go
807 | // good
808 | func (suite *mySuite) TestF() {
809 |     tests := []struct{
810 |         name string
811 |         a, b, c int
812 |     }{
813 |         {"AddPositiveNumbers", 1, 2, 3},
814 |         {"AddZeroToPositiveNumber", 0, 1, 1},
815 |         …
816 |     }
817 |     for _, test := range tests {
818 |         test := test
819 |         suite.Run(test.name, func() {
820 |             suite.Require().Equal(test.c, test.a+test.b)
821 |         })
822 |     }
823 | }
824 | ```
825 | 
826 | Note that `test := test` is necessary to ensure that the variable
827 | captured by the closure is not modified as the for loop proceeds.
828 | 
829 | In side-effectful application code, table-driven tests are often more
830 | confusing than helpful.  If the test body needs more than one or two
831 | conditionals, it may be clearer to just write out every test case
832 | separately.
833 | 
834 | Note that ordinary tests should not use `suite.Run`; the test
835 | method-name should suffice to describe the test.  It's only necessary
836 | for table-driven tests where each sub-case needs a name.
837 | 
838 | ## Error handling
839 | 
840 | > [Khan-specific: this entire section is Khan-specific]
841 | 
842 | We have a [special page all about error
843 | handling](https://khanacademy.atlassian.net/wiki/spaces/ENG/pages/150208513/Goliath+Errors+Best+Practices)!
844 | In summary:
845 | * use `pkg/lib/errors` to create errors
846 | * do not include PII in errors
847 | * do not include `Sprintf`ed strings in errors
848 | * choose the error-kind that best describes your error
849 | * always wrap non-Khan errors before returning them
850 | * log at error level if the request failed, and at warn level if we can
851 |   do fallback
852 | * when creating an error, either return it or log it; do not do both
853 | 


--------------------------------------------------------------------------------