|
7 | 7 |
|
8 | 8 | ## Содержание |
9 | 9 | - [Основные принципы при написании кода](#основные-принципы-при-написании-кода) |
10 | | -- [Пакетный менеджер](#пакетный-менеджер) |
11 | | -- [Форматирование кода](#форматирование-кода) |
12 | | -- [Типизация](#типизация) |
13 | | -- [Импорты](#импорты) |
| 10 | +- [Про код](#про-код) |
14 | 11 | - [Размеры методов, функций и модулей](#размеры-методов-функций-и-модулей) |
| 12 | +- [Импорты](#импорты) |
15 | 13 | - [Файлы `__init__.py`](#файлы-__init__py) |
16 | 14 | - [Докстринги](#докстринги) |
17 | 15 | - [Документация к REST API](#документация-к-rest-api) |
18 | | -- [Про код](#про-код) |
19 | 16 | - [Про Pull Request](#про-pull-request) |
20 | 17 | - [Размер Pull Request](#размер-pull-request) |
| 18 | +- [Пакетный менеджер](#пакетный-менеджер) |
| 19 | +- [Форматирование кода](#форматирование-кода) |
| 20 | +- [Типизация](#типизация) |
21 | 21 |
|
22 | 22 |
|
23 | 23 | ## Основные принципы при написании кода |
|
26 | 26 | - **Очевидность** (представьте, когда подключится новый программист, насколько ему будет понятно, почему именно **так** написан этот код) |
27 | 27 |
|
28 | 28 |
|
| 29 | +## Про код |
| 30 | +**1 действие ~ 1 строка** |
| 31 | + |
| 32 | +На каждой строке надо постараться делать ровно одно действие. |
| 33 | + |
| 34 | +Плохо ❌: |
| 35 | +```python |
| 36 | +# 1. 3 действия на одной строке - 3 вызова функции |
| 37 | +foo_result = foo(bar(spam(x))) |
| 38 | + |
| 39 | +# 2. 3 действия на одной строке - вызов функции foo, get_c, from_b |
| 40 | +foo_result = foo(a=a, b=b, c=get_c(from_b()) |
| 41 | + |
| 42 | +# 3. 3 действия на одной строке - фильтрация по аргументам, условное получение элементов (через or), вызов метода .value |
| 43 | +result = [(a.value() or A, b or B) for a, b in iterator if a < b] |
| 44 | + |
| 45 | +# 4. 4 действия на одной строке - из библиотеки / переменной foo идет получение атрибута bar, получение атрибута spam, получение атрибута hello и вызов calculate_weather |
| 46 | +result = calculate_weather(foo.bar.spam.hello) |
| 47 | +``` |
| 48 | + |
| 49 | +Хорошо ✅: |
| 50 | +```python |
| 51 | +# 1. делаем поочередный вызов каждой функции |
| 52 | +spam_result = spam(x) |
| 53 | +bar_result = bar(spam_result) |
| 54 | +foo_result = foo(bar_result) |
| 55 | + |
| 56 | +# 2. поочередно вызываем функции, результат пишем в переменную и используем ее при вызове foo |
| 57 | +from_b_result = from_b() |
| 58 | +c = get_c(from_b_result) |
| 59 | +foo_result = foo(a=a, b=b, c=c) |
| 60 | + |
| 61 | +# 3. последовательно проводим действия над списком - вначале фильтруем, вызываем метод .value у a, выбираем между элементами (or) |
| 62 | +filtered_result = ((a, b) for a, b in iterator if a < b) |
| 63 | +intermediate_result = ((a.value(), b) for a, b in filtered_result) |
| 64 | +result = [(a or A, b or B) for a, b in intermediate_result] |
| 65 | + |
| 66 | +# 4 . последовательно читаем атрибуты bar, spam, hello и вызываем функцию calculate_weather |
| 67 | +bar = foo.bar |
| 68 | +spam = bar.spam |
| 69 | +hello = spam.hello |
| 70 | +result = calculate_weather(hello) |
| 71 | +``` |
| 72 | + |
| 73 | + |
| 74 | +**Почему?** Потому что код становится более читабельным, не нужно исполнять несколько выражений в голове во время чтения кода. Разбитый до простых атомных операций код воспринимается гораздо лучше, чем сложный уан-лайнер. Постарайтесь упростить свой код настолько, насколько это возможно - код чаще читается, чем пишется. |
| 75 | + |
| 76 | + |
| 77 | +## Размеры методов, функций и модулей |
| 78 | + |
| 79 | +Предельный размер метода или функции - **50** строк. |
| 80 | +Достижение предельного размера говорит о том, что функция (метод) делает слишком много - декомпозируйте действия внутри функции (метода). |
| 81 | + |
| 82 | + |
| 83 | +Предельный размер модуля - **300** строк. |
| 84 | +Достижение предельного размера говорит о том, что модуль получил слишком много логики - декомпозируйте модуль на несколько. |
| 85 | + |
| 86 | +Длина строки - 100 символов. |
| 87 | + |
| 88 | + |
| 89 | +## Импорты |
| 90 | + |
| 91 | +Рекомендуемый способ импортирования - абсолютный. |
| 92 | + |
| 93 | +Плохо ❌: |
| 94 | +```python |
| 95 | +# spam.py |
| 96 | +from . import foo, bar |
| 97 | +``` |
| 98 | + |
| 99 | +Хорошо ✅: |
| 100 | +```python |
| 101 | + |
| 102 | +# spam.py |
| 103 | +from some.absolute.path import foo, bar |
| 104 | +``` |
| 105 | + |
| 106 | +**Почему?** Потому что абсолютный импорт явно определяет локацию (путь) модуля, который импортируется. При релативном |
| 107 | +импорте всегда нужно помнить путь и вычислять в уме локацию модулей `foo.py`, `bar.py` относительно `spam.py` |
| 108 | + |
| 109 | + |
| 110 | +## Файлы `__init__.py` |
| 111 | + |
| 112 | +В `__init__.py` файлах пишем только импорты. |
| 113 | + |
| 114 | +**Почему?** Потому что `__init__.py` - последнее место, в которое посмотрит программист, который будет читать код в будущем. |
| 115 | + |
| 116 | + |
| 117 | +## Докстринги |
| 118 | +Рекомендуем добавлять докстринги в функции, методы и классы. |
| 119 | + |
| 120 | +**Почему?** Потому что программист, который впервые увидит ваш код, сможет быстрее понять, что в нем происходит. |
| 121 | +Код читается намного больше, чем пишется. |
| 122 | + |
| 123 | + |
| 124 | +## Документация к REST API |
| 125 | +Рекомендуемый формат документации - [OpenAPI](https://www.openapis.org). |
| 126 | +Схема для OpenAPI должна генерироваться "на лету", чтобы обеспечивать клиентов API свежими изменениями. |
| 127 | + |
| 128 | +**Почему?** Потому что это один из распространенных форматов для документирования REST API, которая вышла из Swagger. Данный формат документации поддерживается большим количеством клиентов (Swagger, Postman, Insomnia Designer и многие другие). Также, рукописная документация имеет свойство быстро устаревать, а документация, которая генерируется напрямую из кода позволяет не думать о постоянном обновлении документации. |
| 129 | + |
| 130 | + |
| 131 | +## Про Pull Request |
| 132 | +**1 Pull Request = 1 issue** |
| 133 | + |
| 134 | +Один Pull Request должен решать ровно одно issue. |
| 135 | + |
| 136 | +**Почему?** Потому что ревьюверу сложнее держать контекст нескольких задач в голове и переключаться между ними. |
| 137 | + |
| 138 | + |
| 139 | +## Размер Pull Request |
| 140 | +Итоговый дифф PR не должен превышать +/- 600 измененных строк. |
| 141 | + |
| 142 | +Плохо ❌: |
| 143 | + |
| 144 | + |
| 145 | +``` |
| 146 | +Дифф 444 + 333 = 777 |
| 147 | +``` |
| 148 | + |
| 149 | +Хорошо ✅: |
| 150 | + |
| 151 | + |
| 152 | +``` |
| 153 | +Дифф 222 + 111 = 333 |
| 154 | +``` |
| 155 | + |
| 156 | + |
| 157 | +**Почему?** Потому что чем больше PR - тем более он становится неконтролируемым и мерж производится "закрыв глаза и заткнув уши". |
| 158 | +Также, большинству ревьюверов будет сложно воспринять такой объем изменений за один раз. |
| 159 | + |
| 160 | + |
29 | 161 | ## Пакетный менеджер |
30 | 162 |
|
31 | 163 | [poetry](https://python-poetry.org) - менеджер зависимостей и сборщик пакетов |
@@ -135,132 +267,3 @@ ignore_errors = True |
135 | 267 |
|
136 | 268 | ``` |
137 | 269 |
|
138 | | - |
139 | | -## Импорты |
140 | | - |
141 | | -Плохо ❌: |
142 | | -```python |
143 | | -# spam.py |
144 | | -from . import foo, bar |
145 | | -``` |
146 | | - |
147 | | -Хорошо ✅: |
148 | | -```python |
149 | | -
|
150 | | -# spam.py |
151 | | -from some.absolute.path import foo, bar |
152 | | -``` |
153 | | - |
154 | | -**Почему?** Потому что абсолютный импорт явно определяет локацию (путь) модуля, который импортируется. При релативном |
155 | | -импорте всегда нужно помнить путь и вычислять в уме локацию модулей `foo.py`, `bar.py` относительно `spam.py` |
156 | | - |
157 | | - |
158 | | -## Размеры методов, функций и модулей |
159 | | - |
160 | | -Предельный размер метода или функции - **50** строк. |
161 | | -Достижение предельного размера говорит о том, что функция (метод) делает слишком много - декомпозируйте действия внутри функции (метода). |
162 | | - |
163 | | - |
164 | | -Предельный размер модуля - **300** строк. |
165 | | -Достижение предельного размера говорит о том, что модуль получил слишком много логики - декомпозируйте модуль на несколько. |
166 | | - |
167 | | -Длина строки - 100 символов. |
168 | | - |
169 | | - |
170 | | -## Файлы `__init__.py` |
171 | | - |
172 | | -В `__init__.py` файлах пишем только импорты. |
173 | | - |
174 | | -**Почему?** Потому что `__init__.py` - последнее место, в которое посмотрит программист, который будет читать код в будущем. |
175 | | - |
176 | | - |
177 | | -## Докстринги |
178 | | -Рекомендуем добавлять докстринги в функции, методы и классы. |
179 | | - |
180 | | -**Почему?** Потому что программист, который впервые увидит ваш код, сможет быстрее понять, что в нем происходит. |
181 | | -Код читается намного больше, чем пишется. |
182 | | - |
183 | | - |
184 | | -## Документация к REST API |
185 | | -Рекомендуемый формат документации - [OpenAPI](https://www.openapis.org). |
186 | | -Схема для OpenAPI должна генерироваться "на лету", чтобы обеспечивать клиентов API свежими изменениями. |
187 | | - |
188 | | -**Почему?** Потому что это один из распространенных форматов для документирования REST API, которая вышла из Swagger. Данный формат документации поддерживается большим количеством клиентов (Swagger, Postman, Insomnia Designer и многие другие). Также, рукописная документация имеет свойство быстро устаревать, а документация, которая генерируется напрямую из кода позволяет не думать о постоянном обновлении документации. |
189 | | - |
190 | | - |
191 | | -## Про код |
192 | | -**1 действие ~ 1 строка** |
193 | | - |
194 | | -На каждой строке надо постараться делать ровно одно действие. |
195 | | - |
196 | | -Плохо ❌: |
197 | | -```python |
198 | | -# 1. 3 действия на одной строке - 3 вызова функции |
199 | | -foo_result = foo(bar(spam(x))) |
200 | | -
|
201 | | -# 2. 3 действия на одной строке - вызов функции foo, get_c, from_b |
202 | | -foo_result = foo(a=a, b=b, c=get_c(from_b()) |
203 | | -
|
204 | | -# 3. 3 действия на одной строке - фильтрация по аргументам, условное получение элементов (через or), вызов метода .value |
205 | | -result = [(a.value() or A, b or B) for a, b in iterator if a < b] |
206 | | -
|
207 | | -# 4. 4 действия на одной строке - из библиотеки / переменной foo идет получение атрибута bar, получение атрибута spam, получение атрибута hello и вызов calculate_weather |
208 | | -result = calculate_weather(foo.bar.spam.hello) |
209 | | -``` |
210 | | - |
211 | | -Хорошо ✅: |
212 | | -```python |
213 | | -# 1. делаем поочередный вызов каждой функции |
214 | | -spam_result = spam(x) |
215 | | -bar_result = bar(spam_result) |
216 | | -foo_result = foo(bar_result) |
217 | | -
|
218 | | -# 2. поочередно вызываем функции, результат пишем в переменную и используем ее при вызове foo |
219 | | -from_b_result = from_b() |
220 | | -c = get_c(from_b_result) |
221 | | -foo_result = foo(a=a, b=b, c=c) |
222 | | -
|
223 | | -# 3. последовательно проводим действия над списком - вначале фильтруем, вызываем метод .value у a, выбираем между элементами (or) |
224 | | -filtered_result = ((a, b) for a, b in iterator if a < b) |
225 | | -intermediate_result = ((a.value(), b) for a, b in filtered_result) |
226 | | -result = [(a or A, b or B) for a, b in intermediate_result] |
227 | | -
|
228 | | -# 4 . последовательно читаем атрибуты bar, spam, hello и вызываем функцию calculate_weather |
229 | | -bar = foo.bar |
230 | | -spam = bar.spam |
231 | | -hello = spam.hello |
232 | | -result = calculate_weather(hello) |
233 | | -``` |
234 | | - |
235 | | - |
236 | | -**Почему?** Потому что код становится более читабельным, не нужно исполнять несколько выражений в голове во время чтения кода. Разбитый до простых атомных операций код воспринимается гораздо лучше, чем сложный уан-лайнер. Постарайтесь упростить свой код настолько, насколько это возможно - код чаще читается, чем пишется. |
237 | | - |
238 | | - |
239 | | -## Про Pull Request |
240 | | -**1 Pull Request = 1 issue** |
241 | | - |
242 | | -Один Pull Request должен решать ровно одно issue. |
243 | | - |
244 | | -**Почему?** Потому что ревьюверу сложнее держать контекст нескольких задач в голове и переключаться между ними. |
245 | | - |
246 | | - |
247 | | -## Размер Pull Request |
248 | | -Итоговый дифф PR не должен превышать +/- 600 измененных строк. |
249 | | - |
250 | | -Плохо ❌: |
251 | | - |
252 | | - |
253 | | -``` |
254 | | -Дифф 444 + 333 = 777 |
255 | | -``` |
256 | | -
|
257 | | -Хорошо ✅: |
258 | | -
|
259 | | - |
260 | | -``` |
261 | | -Дифф 222 + 111 = 333 |
262 | | -``` |
263 | | -
|
264 | | -
|
265 | | -**Почему?** Потому что чем больше PR - тем более он становится неконтролируемым и мерж производится "закрыв глаза и заткнув уши". |
266 | | -Также, большинству ревьюверов будет сложно воспринять такой объем изменений за один раз. |
|
0 commit comments