-
Notifications
You must be signed in to change notification settings - Fork 821
Adding additional subsections -- feel free to cherry-pick! Feedback welcome. #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c15d98f
23d88f6
26bc828
10c8faa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -207,7 +207,7 @@ you are expecting a string as the argument. | |
| **Good**: | ||
|
|
||
| ```python | ||
| def create_micro_brewery(name: str="Hipster Brew Co."): | ||
| def create_micro_brewery(name: str = "Hipster Brew Co."): | ||
| slug = hashlib.sha1(name.encode()).hexdigest() | ||
| # etc. | ||
| ``` | ||
|
|
@@ -431,3 +431,188 @@ message.send() | |
| ``` | ||
|
|
||
| **[⬆ back to top](#table-of-contents)** | ||
|
|
||
| ### Functions should only be one level of abstraction | ||
|
|
||
| When you have more than one level of abstraction, your function is usually doing too | ||
| much. Splitting up functions leads to reusability and easier testing. | ||
|
|
||
| **Bad:** | ||
|
|
||
| ```python | ||
| def parse_better_js_alternative(code: str) -> None: | ||
| regexes = [ | ||
| # ... | ||
| ] | ||
|
|
||
| statements = regexes.split() | ||
| tokens = [] | ||
| for regex in regexes: | ||
| for statement in statements: | ||
| # ... | ||
|
|
||
| ast = [] | ||
| for token in tokens: | ||
| # Lex. | ||
|
|
||
| for node in ast: | ||
| # Parse. | ||
| ``` | ||
|
|
||
| **Good:** | ||
|
|
||
| ```python | ||
| def parse_better_js_alternative(code: str) -> None: | ||
| tokens = tokenize(code) | ||
| syntax_tree = parse(tokens) | ||
|
|
||
| for node in syntax_tree: | ||
| # Parse. | ||
|
|
||
|
|
||
| def tokenize(code: str) -> list: | ||
| REGEXES = [ | ||
| # ... | ||
| ] | ||
|
|
||
| statements = code.split() | ||
| tokens = [] | ||
| for regex in REGEXES: | ||
| for statement in statements: | ||
| # Append the statement to tokens. | ||
|
|
||
| return tokens | ||
|
|
||
|
|
||
| def parse(tokens: list) -> list: | ||
| syntax_tree = [] | ||
| for token in tokens: | ||
| # Append the parsed token to the syntax tree. | ||
|
|
||
| return syntax_tree | ||
| ``` | ||
|
|
||
| **[⬆ back to top](#table-of-contents)** | ||
|
|
||
| ### Don't use flags as function parameters | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
|
|
||
| Flags tell your user that this function does more than one thing. Functions | ||
| should do one thing. Split your functions if they are following different code | ||
| paths based on a boolean. | ||
|
|
||
| **Bad:** | ||
|
|
||
| ```python | ||
| from pathlib import Path | ||
|
|
||
| def create_file(name: str, temp: bool) -> None: | ||
| if temp: | ||
| Path('./temp/' + name).touch() | ||
| else: | ||
| Path(name).touch() | ||
| ``` | ||
|
|
||
| **Good:** | ||
|
|
||
| ```python | ||
| from pathlib import Path | ||
|
|
||
| def create_file(name: str) -> None: | ||
| Path(name).touch() | ||
|
|
||
| def create_temp_file(name: str) -> None: | ||
| Path('./temp/' + name).touch() | ||
| ``` | ||
|
|
||
| **[⬆ back to top](#table-of-contents)** | ||
|
|
||
| ### Avoid side effects | ||
|
|
||
| A function produces a side effect if it does anything other than take a value in | ||
| and return another value or values. A side effect could be writing to a file, | ||
| modifying some global variable, or accidentally wiring all your money to a | ||
| stranger. | ||
|
|
||
| Now, you do need to have side effects in a program on occasion - for example, like | ||
| in the previous example, you might need to write to a file. In these cases, you | ||
| should centralize and indicate where you are incorporating side effects. Don't have | ||
| several functions and classes that write to a particular file - rather, have one | ||
| (and only one) service that does it. | ||
|
|
||
| The main point is to avoid common pitfalls like sharing state between objects | ||
| without any structure, using mutable data types that can be written to by anything, | ||
| and not centralizing where your side effects occur. If you can do this, you will be | ||
| happier than the vast majority of other programmers. | ||
|
|
||
| **Bad:** | ||
|
|
||
| ```python | ||
| # Global variable referenced by following function. | ||
| # If another function used this name, now it'd be an array and could break. | ||
| name = 'Ryan McDermott' | ||
|
|
||
| def split_into_first_and_last_name() -> None: | ||
| global name | ||
| name = name.split() | ||
|
|
||
| split_into_first_and_last_name() | ||
|
|
||
| print(name) # ['Ryan', 'McDermott'] | ||
| ``` | ||
|
|
||
| **Good:** | ||
| ```python | ||
| def split_into_first_and_last_name(name: str) -> None: | ||
| return name.split() | ||
|
|
||
| name = 'Ryan McDermott' | ||
| new_name = split_into_first_and_last_name(name) | ||
|
|
||
| print(name) # 'Ryan McDermott' | ||
| print(new_name) # ['Ryan', 'McDermott'] | ||
| ``` | ||
|
|
||
| **[⬆ back to top](#table-of-contents)** | ||
|
|
||
| ### Don't write to global functions | ||
|
|
||
| Polluting globals is a bad practice in many languages because you could clash | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand this one. The function However, you could do the following: This would modify the global namespace, which is seldom necessary and would be considered bad practice (use modules instead). Feel free to open a new pull request if I have misunderstood this section.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you're right. Subsection adapted from https://github.com/jupeter/clean-code-php#dont-write-to-global-functions. I suppose PHP requires that you explicitly declare namespaces, so the same module-scoping policy doesn't apply? |
||
| with another library, and the user of your library would be none-the-wiser | ||
| until they get an exception in production. Let's think about an example: what | ||
| if you wanted to hace a configuration array? You could write a global function like | ||
| `config()`, but it could clash with another library that tried to do the same thing. | ||
|
|
||
| **Bad:** | ||
|
|
||
| ```python | ||
| def config() -> dict: | ||
| return { | ||
| 'foo': 'bar', | ||
| } | ||
| ``` | ||
|
|
||
| **Good:** | ||
|
|
||
| ```python | ||
| from typing import Any, Dict, Optional | ||
|
|
||
| class Configuration | ||
| def __init__(self, configuration: Dict[str, Any]): | ||
| self._configuration = configuration | ||
|
|
||
| def get(self, key: str) -> Optional[str]: | ||
| return self._configuration.get(key) | ||
| ``` | ||
|
|
||
| Load configuration and create instance of `Configuration` class: | ||
|
|
||
| ```python | ||
| configuration = Configuration( | ||
| { | ||
| 'foo': 'bar', | ||
| } | ||
| ) | ||
| ``` | ||
| And now, you may use this instance of `Configuration` in your application. | ||
|
|
||
| **[⬆ back to top](#table-of-contents)** | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel this is too similar to section
Functions should do one thingThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. Adapted from https://github.com/jupeter/clean-code-php#functions-should-only-be-one-level-of-abstraction -- it does appear to be a rephrasing of
Functions should do only one thing.