Правильное наименование переменных, функций, методов и классов — один из важнейших атрибутов элегантного и чистого кода, четко отражающего намерения программиста, без предположений о том, что имелось в виду.
В этой статье мы поговорим о коде, прямо противоположном описанному выше, — о коде, написанном небрежно или бездумно.
Эта статья — маленькая исповедь, потому что у меня, как и у любого другого программиста, тоже написал такой код в прошлом (на самом деле, я до сих пор иногда пишу плохой код, хотя рефакторинг делает его намного лучше). В этом нет ничего страшного, пока мы понимаем, что над этим нужно работать.
Давайте начнем.
Переменные
Один из самых раздражающих типов переменных — это переменные, которые дают ложное представление о характере данных, которые они хранят.
Библиотека 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. Мартин Фаулер — Рефакторинг: улучшение дизайна существующего кода