Справка по рефакторингу кода - как реорганизовать валидации - PullRequest
0 голосов
/ 21 декабря 2008

У нас есть веб-приложение, которое принимает пользовательский ввод или поиск в базе данных для формирования некоторых операций с некоторыми физическими ресурсами. Дизайн можно просто представить в виде следующей диаграммы:

пользовательский ввод <=> объект модели <=> хранилище базы данных

проверки необходимы при запросе, поступающем от пользовательского ввода, но НЕ при поступлении от обращений к поиску в базе данных (поскольку, если запись существует, эти атрибуты уже должны быть проверены ранее). Я пытаюсь реорганизовать код так, чтобы проверки происходили в конструкторе объектов, а не по-старому (отдельные процедуры проверки)

Как бы вы решили, какой путь лучше? (Принципиальное отличие метода 1 (старый способ) и 2 состоит в том, что проверки в 1 не являются обязательными и не связаны с созданием объекта, но 2 связывает их и делает их обязательными для всех запросов)

Вот два примера фрагментов кода для дизайна 1 и 2:

Метод 1:

# For processing single request.
# Steps: 1. Validate all incoming data. 2. instantiate the object.
ValidateAttribures(request) # raise Exceptions if failed
resource = Resource(**request)

Метод 2:

# Have to extract out this since it does not have anything to do with
# the object.
# raise Exceptions if some required params missing.
# steps: 1. Check whether its a batching request. 2. instantiate the object.
#           (validations are performed inside the constructor)
CheckIfBatchRequest(request) 
resource = Resource(**request) # raise Exceptions when validations failed

В пакетном запросе: Способ 1:

# steps: 1. validate each request and return error to the client if any found.
#        2. perform the object instantiate and creation process. Exceptions are
#           captured.
#        3. when all finished, email out any errors.
for request in batch_requests:
    try:    
        ValidateAttribute(request)
    except SomeException, e:
        return ErrorPage(e)
errors = []
for request in batch_requests:
    try:
        CreatResource(Resource(**request), request)
    except CreationError, e:
        errors.append('failed to create with error: %s', e)
email(errors)

Метод 2:

# steps: 1. validate batch job related data from the request.
#        2. If success, create objects for each request and do the validations.
#        3. If exception, return error found, otherwise, 
#           return a list of pairs with (object, request)
#        4. Do the creation process and email out any errors if encountered.
CheckIfBatchRequest(request)
request_objects = []
for request in batch_requests:
    try:
        resource = Resource(**request)
    except SomeException, e:
        return ErrorPage(e)
    request_objects.append((resource, request))
email(CreateResource(request_objects)) # the CreateResource will also need to be refactored.

Плюсы и минусы, как я вижу здесь:

  1. Метод 1 следует более близко к бизнес-логике. Никакой избыточной проверки не происходит, когда объекты поступают из базы данных. Процедуры проверки более удобны в обслуживании и читаются.
  2. Метод 2 облегчает и очищает вызывающего абонента. Проверки являются обязательными, даже если из db lookup. Валидации менее понятны и читаются.

Ответы [ 2 ]

1 голос
/ 21 декабря 2008

Выполнение проверки в конструкторе на самом деле не «путь Джанго». Поскольку данные, которые необходимо проверить, поступают со стороны клиента, использование новых форм (возможно, с ModelForm ) является наиболее идиоматическим методом проверки, поскольку он охватывает все ваши проблемы. в одном API: он обеспечивает разумные значения по умолчанию для проверки (с возможностью простой настройки), а формы моделей объединяют сторону ввода данных (html-форму) с фиксацией данных (model.save ()).

Тем не менее, звучит так, как будто вы имеете дело с устаревшим проектом; Возможно, вам не по силам переписать всю обработку ваших форм, чтобы использовать новые формы, по крайней мере, на начальном этапе. Итак, вот мои мысли:

Прежде всего, это не «не-Djangonic», чтобы поставить некоторую проверку в самой модели - в конце концов, отправка html-форм может быть не единственным источником новых данных. Вы можете переопределить метод save () или использовать сигналов , чтобы либо очистить данные при сохранении, либо выдать исключение для недопустимых данных. В долгосрочной перспективе Django будет проходить валидацию модели, но ее пока нет; тем временем вы должны считать это «безопасностью», чтобы гарантировать, что вы не передадите неверные данные в вашу БД. Другими словами, вам все еще нужно проверять поле за полем перед фиксацией, чтобы вы знали, какую ошибку показывать своим пользователям при неверном вводе.

То, что я хотел бы предложить, это. Создайте новые классы форм для каждого элемента, который необходимо проверить, даже если вы не используете их изначально. Малкольм Трединник обрисовал методику проверки модели с использованием хуков, предусмотренных в системе форм. Читайте об этом (это действительно довольно просто и элегантно) и подключайтесь к своим моделям. После того, как вы определили классы newforms и заработали, вы увидите, что это не очень сложно - и на самом деле значительно упростит ваш код - если вы извлечете существующие шаблоны форм и соответствующую проверку, и обработаете POST формы с помощью рамки формы. Есть некоторая кривая обучения, но API форм очень хорошо продуман, и вы будете благодарны за то, насколько чище он сделает ваш код.

0 голосов
/ 21 декабря 2008

Спасибо Дэниелу за ваш ответ. Специально для API newforms я определенно потрачу время на изучение этого вопроса и посмотрим, смогу ли я использовать его для достижения долгосрочных преимуществ. Но только ради того, чтобы моя работа была выполнена для этой итерации (уложиться в крайний срок до EOY), мне, вероятно, все равно придется придерживаться существующей унаследованной структуры, в конце концов, в любом случае, я получу то, что хочу, только это Я хочу сделать его нормальным и чистым, насколько это возможно, не ломая слишком много.

Похоже, что выполнение проверок в модели не является слишком плохой идеей, но в другом смысле мой старый способ выполнения проверок в представлениях против запроса также кажется близким к концепции инкапсуляции их в API newforms (проверка данных). отделен от создания модели). Как вы думаете, это нормально, просто сохранить мой старый дизайн? Для меня более логично коснуться этого с помощью API newforms, а не манипулировать ими прямо сейчас ...

(Ну, я получил это предложение по рефакторингу от моего рецензента кода, но на самом деле я не уверен, что мой старый способ нарушает какие-либо шаблоны mvc или слишком сложен в обслуживании. Я думаю, что мой способ имеет больше смысла, но мой рецензент думал, что обязательная проверка и модель создание вместе имеет больше смысла ...)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...