Правильное наименование переменных, функций, методов и классов — один из важнейших атрибутов элегантного и чистого кода, четко отражающего намерения программиста, без предположений о том, что имелось в виду.

В этой статье мы поговорим о коде, прямо противоположном описанному выше, — о коде, написанном небрежно или бездумно.
Эта статья — маленькая исповедь, потому что у меня, как и у любого другого программиста, тоже написал такой код в прошлом (на самом деле, я до сих пор иногда пишу плохой код, хотя рефакторинг делает его намного лучше). В этом нет ничего страшного, пока мы понимаем, что над этим нужно работать.

Давайте начнем.

Переменные

Один из самых раздражающих типов переменных — это переменные, которые дают ложное представление о характере данных, которые они хранят.

Библиотека requests чрезвычайно популярна среди разработчиков Python, и если вы когда-либо искали что-то, связанное с requests, вы наверняка наткнулись на что-то вроде этого:

import requests
req = requests.get(‘https://api.example.org/endpoint')
req.json()

Всякий раз, когда я это вижу, я чувствую раздражение и даже не из-за укороченного имени, а из-за того, что имя переменной не соответствует тому, что хранится в этой переменной.

Когда вы делаете запрос requests.Request, вы получаете ответ requests.Response, поэтому отразите это в своем коде:

response = requests.get(‘https://api.example.org/endpoint')
response.json()

Не r, не res, не resp и уж точно не req, именно response. res, r, resp — это все переменные, содержимое которых можно понять, только взглянув на их определения, а зачем перескакивать к определениям, когда можно изначально дать подходящее имя?

Давайте посмотрим на другой пример, но теперь из Django:

users_list = User.objects.filter(age__gte=22)

Когда вы видите users_list где-то в коде, вы совершенно справедливо ожидаете, что сможете сделать это:

users_list.append(User.objects.get(pk=3))

но нет, вы не можете этого сделать, так как .filter() возвращает QuerySet:

Traceback (most recent call last):
# …
# …
AttributeError: ‘QuerySet’ object has no attribute ‘append’

Если для вас очень важно указать суффикс, то укажите хотя бы тот, который отражает реальную ситуацию:

users_queryset = User.objects.all()
users_queryset.order_by(‘-age’)

тоже ладно, потому что для Django привычны такие сокращения (_qs):

users_qs = User.objects.all()

Если вы действительно хотите написать именно _list, то позаботьтесь о том, чтобы list действительно попало в переменную:

users_list = list(User.objects.all())

Указание типа данных, которые содержит переменная, часто является плохой идеей, особенно когда вы имеете дело с динамическими языками, такими как Python. В случаях, когда очень нужно отметить, что объект является контейнерным типом данных, достаточно просто указать имя переменной во множественном числе:

users = User.objects.all()

Рассмотрим другой пример:

info_dict = {‘name’: ‘Isaak’, ‘age’: 25}
# …
# … 
info_dict = list(info_dict)
# …
# …

Вы видите dict, и вы можете сделать это:

for key, value in info_dict.items():
    print(key, value)

Вместо этого вы получите исключение, потому что вас ввели в заблуждение, и вы поймете это, только если вы перейдете к определению переменной и прочитаете весь код сверху вниз, вплоть до раздела, с которого вы начали переход — это цена таких переменных.

Таким образом, когда вы указываете в имени переменной тип хранимых в ней данных, вы по сути являетесь гарантом того, что эта переменная должна содержать указанный тип данных в любой момент времени. время выполнения программы. Почему вы должны брать на себя эту ответственность, если это прямая обязанность интерпретатора или компилятора? Вы не должны! Лучше потратить время на размышления о хорошем имени переменной, чем пытаться выяснить, почему переменные ведут себя не так, как вы ожидаете.

В приведенном выше примере выбор имени переменной довольно неудачен, и можно было бы дать имя, более точно выражающее контекст (не нужно бояться использовать имена, относящиеся к предметной области), но даже в этом случае , вы можете улучшить этот код:

info_dict = {‘name’: ‘Isaak’, ‘age’: 25}
# …
# … 
info_keys = list(info_dict)
# …
# …

или даже так, что более идиоматично:

info_dict = {‘name’: ‘Isaak’, ‘age’: 25}
# …
# … 
info_keys = info_dict.keys()
# …
# …

Другой тип раздражающих переменных — это переменные с сокращенным именем.

Вернемся к requests и рассмотрим этот код:

s = requests.Session()
# …
# … 
s.close()

Это пример ненужного сокращения имени переменной. Это ужасная практика, и ее ужас становится еще более очевидным, когда такой код занимает более 10–15 строк кода.

Гораздо лучше писать как есть, а именно:

session = requests.Session()
# …
# …
session.get(‘https://api.example.org/endpoint')
# …
# …
session.close()

or

with requests.Session() as session:
    session.get(‘https://api.example.org/endpoint')

Вы можете возразить, что это более многословный вариант, но я вам отвечу, что он окупается, когда вы читаете код и сразу понимаете, что session — это Session.

Вы поймете это по переменной s, не глядя на ее определение?

Методы

Умное именование функций и методов — это то, что приходит только с опытом проектирования API, и поэтому часто можно встретить случаи, когда методы ведут себя не так, как вы ожидаете.

Рассмотрим пример:

>>> person = Person()
>>> person.has_publications()
[‘Post 1’, ‘Post 2’, ‘Post 3’]

В нашем коде мы выразили очень четкий вопрос: «Есть ли у этого человека публикации?», но какой ответ мы получили? Мы просили список публикаций человека?

Название этого метода подразумевает, что возвращаемое значение должно быть логического типа, а именно True или False:

>>> person = Person()
>>> person.has_publications()
True

Мы можем использовать более подходящее имя метода для получения публикаций:

>>> person.get_publications()
[‘Post 1’, ‘Post 2’, ‘Post 3’]

or

>>> person.publications()
[‘Post 1’, ‘Post 2’, ‘Post 3’]

Нам часто нравится называть программирование творческой деятельностью, и это действительно так. Однако, если вы пишете не читаемый код, а потом оправдываете это «творчеством», то у меня для вас плохие новости.

Подробнее можно прочитать в моем личном блоге: https://isaak.dev

Twitter: https://twitter.com/likid_geimfari
GitHub: https://github.com/lk-geimfari
Telegram: https://t.me/isaak_dev

дальнейшее чтение

Я оставляю этот список выдающейся актуальной литературы, написанной известными профессионалами в этой области, для дальнейшего изучения вопроса:

1. Роберт Мартин — Чистый код
2. Роберт Мартин — Чистая архитектура
3. Роберт Мартин — Чистый кодер: Кодекс поведения для профессиональных программистов
4. Мартин Фаулер — Рефакторинг: улучшение дизайна существующего кода