Еще не могу удержаться:
- хорошая система исключений.
- Во первых, информативный текст. В примере я бросал простой assert. По хорошему нужно приложить к нему второй параметр. Что-то вроде
assert isinstance(value, self.type), ‘Attribute %r must be instance of %r type, got %r’%(self.name, setlf.type, type(value))
Очень облегчает анализ ошибки
- Во вторых, никогда не ловите и не бросайте Exception. except Exception съест в том числе и непредвиденные ошибки - NameError например. Если не знаете тип исключения - RuntimeError был сделан как раз для вас.
- Если ловите, скажем, ValidationError на save и хотите превратить его в TransactionError - сделайте так, чтобы ваш TransactionError мог рассказать о вложенном исключении, которое это проблему вызвало. Вложеные тип, значение и, главное, stack trace. Опять же поможет.
- логирование.
- Модуль logging хорошо - всегда его используйте. Имейте много логеров. Год назад
накропал статейку Пользуюсь практически без изменений - разве что по рекомендации Макса Ищенко добавил mod_logger. В девелоперской конфигурации обязательно логируйте помимо всего прочего на консоль. В production - обязательно в файл. Его вам хотя бы по email перешлют. Файлы ротировать и сохранять достаточно долгое время. Чтобы на тот момент, когда вам клиент нажалуется - у него логи все еще были.
- принты не используйте. Сам их часто вставляю - но только для отладки. В svn они не попадают. Хотели даже pre-commit hook вставить, который питоновские файлы бы парсил и если увидел незакомментареный print - commit бы не допускал. Руки не доходят, по простому незлым тихим словом поддерживаем порядок.
- repr. Очень полезная штука. Практически у каждого класса должен быть свой переопределенный __repr__. Который нормально описывает класс. Например, для пресловутого объекта из БД по имени “пользователь” возвращается строка <User ‘
vpupkin@gmai.com’> если email - уникальный индекс. Опять же сокращает отладку. Обратите внимание, что email в кавычках - стандартная реализация repr для строки. Позволяет наглядно показать, есть ли в параметре пробелы или таки нет. Тоже сохраняет время. repr вызывается при ‘%r’%arg, а при ‘%s’%arg зовется str - который может иметь (и зачастую так и есть) совершенно другую реализацию. При логировани и бросании исключений используйте именно repr. Экономит время, особенно когда паренек из support team подходит с вопросом - а почему у клиента не работает. У этого паренька иногда тоже воспроизводится - если он на том же environment смог поймать проблему. Но нет отладчика. Исходников по умолчанию тоже нет. Перенастроить мое девелоперское окружение на то, что вертится у заказчика - пара часов работы в лучшем случае. В худшем - сутки (и это при том, что заказчики сидят в своем интранет, к которому мы имеем достаточно свободный доступ - просто чудеса). Зато есть логи. Чем они информативней (молчат о стандартных ситуациях и подробно рассказывают о возникшей проблеме - тем быстрее она решается)
- это позволяет свести отладку к минимуму. Да, я сам тоже ей пользуюсь. import pdb;pdb.set_trace() Получаю вполне приличную питоновскую консоль в проблемном месте. Все, что я прошу у системы - информативное (помните про repr). Отлаживать долго не нужно. Чаще нужно именно войти питоном куда следует и поспрашивать. Стек, окружение, то-се. Не нужно трассировать глубокие стеки вызовов - логи скажут. После вырабатывания привычки к подобному стилю здорово экономишь свое время. Как и привычка к написанию юниттестов спасает от часов тупой отладки.
- Ключевое слово - привычка. Привык, и пишу мало кода, который делает много дела. Привык - и затягиваю сдачу истории до тех пор, пока она не будет готова с моей точки зрения. В результате разработка получается сбалансированной и быстрой.
Привык - и выдаю всегда только хороший (по крайней мере с моей точки зрения) код.
P.S. Конечно, все вышесказанное - только лишь моя точка зрения. Каждый может не согласиться, оспорить или противопоставить свою. С удовольствием выслушаю.
baluСпасибо за роль хорошего оппонента. Ответы на твои вопросы помогли взглянуть на проблему немного с другой стороны.