Рефакторинг и сопровождение кода — сложная и грязная работа. К счастью, есть методы, помогающие незадачливому разработчику, которому поручено заботиться о разросшейся кодовой базе: конечно, разработка через тестирование, ведущая к тщательно поддерживаемому набору тестов, является отличной целью, но что делать с трудно тестируемым и унаследованным кодом? или при развертывании экспериментальных функций?
Рассмотрите флаг функции!
Концепция очень проста: по сути, это просто условие «если» вокруг рассматриваемого кода. Это обеспечивает два пути кода: один для нового реорганизованного кода и один для предыдущего кода.
#in settings.py NEW_CODE_FEATURE_FLAG = True #somewhere else in the code: if NEW_CODE_FEATURE_FLAG: # do this experimental code else: # revert to the previous code
Это хорошо и хорошо, и если мы находимся в веб-контексте, мы можем включить флаг функции для небольшого сегмента нашего трафика и посмотреть журналы на предмет результата — откат (и даже автоматический возврат), если есть какие-либо признак проблем. Если функция работает должным образом, мы очищаем ее, удаляя флаг и блок if.
Но можем ли мы сделать это аккуратнее? Смешение бизнес-логики и кода рефакторинга не является идеальным. Рассмотрим этот пример с использованием менеджера контекста:
# in a settings.py file: THIS_CODE_FLAG = LEGACY_CODE --- print 'Legacy code block start' with Feature_Flag(mode=THIS_CODE_FLAG, this_code=LEGACY_CODE): print 'executing legacy code block' r = do_complicated_function() print 'Legacy code block end' print 'Refactored code block start' with Feature_Flag(mode=THIS_CODE_FLAG, this_code=NEW_CODE): print('executing refactored code block') r = do_refactored_complicated_function() print('Refactored code block end')
Флаг кода здесь установлен для запуска блока «устаревшего кода», а не блока «нового кода»; следовательно, вывод:
Legacy code block start executing legacy code block Legacy code block end Refactored code block start Refactored code block end
Выполнить оба блока и подтвердить, что результаты одинаковы
Это здорово: бизнес-логика довольно хорошо отделена от тестирования — но что произойдет, если мы захотим запустить оба блока и убедиться, что результаты одинаковы?
Да, у нас могут быть временные переменные; и поместите assert(a==b) в конце двух блоков. Но не было бы неплохо использовать для этого менеджер контекста? Это позволило бы сохранить хорошее отделение кода рефакторинга от бизнес-логики.
Этот суть делает именно это: оба блока выполняются и сравниваются — просто установите флаг в ASSERT_CODE_BLOCK_RESULTS_SAME и сохраните результат блока обратно в менеджер контекста — если они отличаются, возникнет исключение.
# in a settings.py file: THIS_CODE_FLAG = ASSERT_CODE_BLOCK_RESULTS_SAME ---- with Feature_Flag(mode=THIS_CODE_FLAG, this_code=LEGACY_CODE) as f: r = do_complicated_function() f.block_result(r) with Feature_Flag(mode=THIS_CODE_FLAG, this_code=NEW_CODE) as f r = do_refactored_complicated_function() f.block_result(r)
Благодаря этому вдохновению stackoverflow.
код: https://gist.github.com/julzhk/7d5f637190e9a3ca9d67cb801392162c
Это всего лишь пример проверки концепции (есть проблема изменяемых ключей и этой уродливой глобальной переменной…) для python 2.7 (о ужас!); содержимое может осесть в пути; Используйте на свой риск.