Примечание: Этот пост будет обновлен со временем
API Backend Programming может быть стрессовым и повторяющимся. В течение последнего года, повторную повторную факторину и переписали более 10 тысяч линий рекордного кодекса, я понял важность после правильной структуры/дисциплины во время кодирования Backeng API. К счастью, концепция Монадическое программирование уже существовало на языках, таких как haskell и angularjs.
Этот пост покажет вам шаблон для реализации кодирующей дисциплины, такой как Monads в Python, которая в случае последующей необходимости позволит вам иметь нулевые проблемы выполнения и минимальную к нему никакой бойной таблички в вашем коде. Для меня это помогло мне уменьшить мою тому объема бэкэнда до 1/3 его размера, усиливая регистрацию и стабильность, добавленные задержки с нулевым характеристиками.
Создать монадский класс Монады являются чистыми функциями. Это неявно означает, что тип ввода, который он принимает и тип вывода, он производит, будет одинаковым. В этом случае это состояние – это Dict {}. Это также означает, что у вас не может быть исключения или нет типа возврата в ваших функциях.
Наш монадский класс определен, чтобы иметь: государство : Это текущее состояние, которое мы имеем в нашем монаде, который представляет данные, которые мы в настоящее время обрабатываем. Это также аргумент, который мы переходим к функциям в монаде. Мы создаем класс MondaiC, который занимается наклонным в качестве первоначального состояния. Для API Backend Code это состояние может быть вашим параметрам запроса. Подумайте об этом, как будто вы передаете одни и те же переменные в функции, только что они обернуты в дикт, а имена переменных являются ключами в диктоме.
FNS : Он имеет список функций, которые являются указателями функции для выполнения функций для выполнения в порядке. Например, вы можете разработать ваш поток Sign_up AS: [process_request_params, check_username_password, create_token, etter_session]
.Execute позвонит эти функции в контуре до достижения конечного состояния. Заключительное состояние должно эффективно быть вашим выходом ответа. Вот что похоже на поток из одного состояния в другое состояние
EFN : Предположим, ваш код ломается между функцией в трубопроводе. Функция ошибки EFN Обрабатывают текущее состояние монады и выпустите ошибку, поскольку вам требуется в ответ. Это сохраняет вас от получения 500 ошибок сервера от Backend.
Наш монадический код опирается на параметр «Статус» в состоянии CONTIC, чтобы получить «Ошибка» отчетов в разделе «Функции».
class MaybeErrorMonad(object): def __init__(self, state, fns, efn): self.state = state # current state (dict) in monadic pipeline self.fns = fns # a list of functions in order of execution self.error_fn = efn # error function that reports any error, based on self.state self.finish = False # a flag to indicate that the self.state is final state def value(self): return self.state def execute(self): # a wrapper class that does execution of functions on current self.state in order def _fun(): if self.finish: return self.state computation = self.state for i in self.fns: computation = i(computation) if computation.get("status") == "error": return self.error_fn(computation) self.state = computation self.finish = True return self.state return _fun()
Далее мы определяем некоторые функции для тестирования нашего монады. Я добавил ошибку_handler_wrapper Функция обертки Который гарантирует, что наши функции всегда возвращают правильный ответ в Dict, если что-то сломается в середине. Вы можете разработать эту функцию, чтобы включить журналы с именем функции и аргументами с текущими параметрами для лучшего отладки в производстве. Мы также определяем нашу функцию настраиваемой ошибки для вывода нашей ошибки, когда мы получаем статус ошибки Midway.
def err_handler_wrapper(fun): # a error handler wrapper function to report any execution errors in dict def wrapper(*args): try: state = fun(*args) except: return {"status": "error", "reason": "Girlfriend not found"} return state return wrapper def efn(state): return {"status": "Rejected :'(", "reason":state.get('reason') } @err_handler_wrapper def get_flowers(state): print "got flowers for %s"%state['girlfriend'] state.update({"flowers": True}) return state @err_handler_wrapper def get_chocolates(state): print "got chocolates for %s"%state['girlfriend'] state.update({"chocolates": True}) return state @err_handler_wrapper def propose(state): if state.get('flowers') and state.get('chocolates'): return {"status": "Success! she said yes"} return {"status": "she said no"}
Давайте запустим наш пример, где парень пытается предложить его раздавить. Если он покупает просто цветы, он будет отклонен. Если он покупает шоколад и цветы, он принимается. Если в исходном состоянии нет «подруги», не ошибка.
# CASE 1 to_do = [get_flowers ,get_chocolates, propose] initial_state = {'girlfriend': 'Alice'} executor = MaybeErrorMonad(initial_state, to_do, efn) result = executor.execute() print "CASE 1: %s \n"%str(result) #CASE 2 initial_state = {} # no girlfriend executor = MaybeErrorMonad(initial_state, to_do, efn) result = executor.execute() print "CASE 2: %s \n"%str(result) # CASE 3 to_do = [get_flowers, propose] # rejection beacuse of not enough efforts :P initial_state = {'girlfriend': 'Alice'} executor = MaybeErrorMonad(initial_state, to_do, efn) result = executor.execute() print "CASE 3: %s \n"%str(result)
И … Вот наш выход, как и ожидалось.
Это был довольно простой пример. Представьте себе мощность теперь возможность выполнять огромные функции в простой списке последовательных Todo с минимальным ветвлением. ПОПРОБУЙ ЭТО СЕЙЧАС !!!
В следующем обновлении мы узнаем, как структурировать наши данные Dict и как спрашивать исключения и получать параметры из правильного контекста выполнения.
Для получения дополнительных представлений об устранении котельной, прочитайте это: HyperCubed !!
Узнайте больше о монаде здесь: – Монадическое программирование Монадс В Python: Пимонад
Оригинал: “https://dev.to/javalin/zero-boilerplate-zero-runtime-errors-coding-with-monads-26n9”