Pull to refresh

Comments 21

Лучше делать проверку корректности данных в интерфейсе. Не загромождайте бизнес-логику из-за того, что вы не доверяете данным.


Это он серьезно? Или я что-то в контексте упустил?
Как можно валидацию данных перемещать в UI и не делать в слое бизнес-логики?
Да, серьёзно. Посмотрите — там справа указаны комментарии автора к этому пункту. Но про UI вы уже сами надумали.
Как раз ваш перевод точен и передает только то, что написал автор. Слово в слово.

И я таки не согласен с выносом проверки данных из бизнес-логики.
Доверять данным нельзя по определению, и проверять их надо на всех возможных уровнях, иначе аукнется рано или поздно большой (или маленькой) дырой в security.
С этим полностью соглашусь. На днях перечитывал «24 смертных греха компьютерной безопасности» (М. Ховард, Д. Лебланк, Дж. Вьега) и осознал, что лишняя паранояй никогда не будет лишней. Возможно, автор имел ввиду проверку на входах модулей/компонентов, которая позволит обеспечить «безопасную зону» внутри него.
Автор имел в виду, что всё должно быть в меру.

Разработка спецификации на компонент — большое дело, понять что в него может и не может приходить — нетривиальная задача и, конечно же, она должна быть сделана, если вы хотите добиться того, чтобы всё работало.

А вот защищать компонент от самого себя — не стоит, проверки тоже являются кодом и в них тоже могут быть ошибки. Более того, их обилие может скрыть реальные ошибки и/или породить беспечность (а нафиг мне знать что в этой переменной? в случае чего проверка выкинет ошибку… только вот беда: если вы даже не знаете пришло ли вам число или строка, то вы легко можете пропустить, скажем, отрицательное число, которое вам всё программу развалит).
Имелось в виду, что проверять данные должен тот модуль системы, который их принимает. Например, форма. В любом адекватном движке форм (Симфони, Зенд, моем кастомном ;-) валидаторы вставляются прямо в форму, а в контроллере их нет. Если говорить о декстопах, то ситуация там должна быть аналогичной, хотя это и не практикуется в классике.

Если автономный код принимает на вход неконтроллируемые значения, он должен их проверить. В противном случае проверять данные нет смысла, если вы пишете не космос, атом или медицину. Контроллер — это никак не автономный код, который принимает неконтроллируемые значения. А вот слой интерфейса — это именно оно.

Надеюсь удалось донести мысль :)
Контроллер — это никак не автономный код, который принимает неконтроллируемые значения.

Это зависит исключительно от декомпоновки приложения. Например, в asp.net mvc контроллер как раз принимает на вход значения извне.

Но дело даже не в этом. Идея защитного программирования в том, что любой код, вызов которого вы не контролируете, может быть рано или поздно вызван не так, как вы ожидаете, и вы должны от этого защищаться. В современных «традиционных» приложениях границ безопасности намного больше одной. Например, для многослойного веб-приложения здесь будет:
  • клиентская валидация (нужна исключительно для обеспечения комфорта пользователя)
  • валидация на входе в серверную часть (потому что js всегда можно отключить + http-запрос вообще можно послать откуда угодно)
  • валидация на входе в апп-сервер (если приложение имеет более одного слоя)
  • валидация на входе в объект бизнес-логики (потому что никто никогда не знает, откуда именно он вызван и насколько аккуратен он был)
  • валидация в БД — если мы реально параноики или если у нас нет уверенности, что в БД пишут только через наш же серверный слой
Подождите, причем тут клиент и БД. Речь во-первых о коде, который работает в рамках одного процесса. Это как бы не явно подразумевается. Для БД наш бэкэнд — как раз источник неконтроллируемых данных. Тоже самое и в связке киент-сервер. Но когда речь идет о «теле сайта», т.е. все, что выполняется в рамках одного процесса PHP/Ruby/Python/anyCGI и при этом написано для этого сайта, а не является отдельной библиотекой (т.е. view, controller – да, стороннее ORM — нет) – все эти части не просто могут, а должны доверять друг другу (оставляя проверки только на входе), иначе весь ваш код будут сполшные повторяющиеся проверки, а это плохо (если не атом, медицина, космос). Опять же не уверен, что мысль донес, но постарался.
Это как бы не явно подразумевается.

Кем это подразумевается? Или это методология QDD работает только и исключительно в таких условиях?

Но вообще то, что вы пытаетесь донести — это концепция security boundary, гласящая, что проверки выполняются один раз на пересечении публичного интерфейса модуля, а все внутренние по отношению к модулю объекты могут проверками не заниматься. Что характерно, у меня именно так и написано, иначе бы проверка была реально в каждом классе/методе/функции. Я просто привел наиболее типичные варианты расположения security boundary.

Но вот предполагать, что весь код «в теле сайта» — это одна зона доверия — ошибочно. Так можно делать только в том случае, если кода достаточно мало, и пишет его один человек. В противном случае, вы рано или поздно начнете делить его на слои по ответственности — и на каждой границе слоя вам понадобятся те или иные проверки, потому что вы никогда не можете знать, что проверил автор вызывающего вас кода.
Не вырывайте фраз из контекста. Связь вашего комментария с цитатой моего предложения мне не понятна. Это предложение не имеет смысл без предыдущего, а оно ничего не говорит про QDD.

Но вот предполагать, что весь код «в теле сайта» — это одна зона доверия — ошибочно. Так можно делать только в том случае, если кода достаточно мало, и пишет его один человек.

Не важно, сколько людей пишут. Важно, где граница автономного (от сайта) модуля — библиотеки. Про security boundary — это именно то, что пытаюсь донести и я, и автор. Проверили на входе и юзаем дальше где надо в рамках единого кода. Каждый вход в библиотеку — это новый вход и новые проверки. Контроллер бить библиотекой не может и проверок в нем быть не должно, кроме случая отхода от ООП и MVC, когда контроллер напрямую работает с GET-параметрами, куками или другими данными, приходящими отпользователя. Подробнее тут написал.
Не вырывайте фраз из контекста. Связь вашего комментария с цитатой моего предложения мне не понятна.

Связь очень простая: вы пишете, что «подразумевается, что весь код в одном процессе», а я спрашиваю, кем это подразумевается.

Не важно, сколько людей пишут.

Важно-важно. Чем больше людей, тем более вероятность ошибки.

Контроллер бить библиотекой не может и проверок в нем быть не должно, кроме случая отхода от ООП и MVC

Давайте не будем начинать холивар за правильные реализации MVC? Просто поверьте мне, что бывают другие декомпоновки, и они не менее «канонические».

Вы-то, возможно, и пытаетесь донести идею security boundary, но в посте явно написано «Лучше делать проверку корректности данных в интерфейсе. Не загромождайте бизнес-логику из-за того, что вы не доверяете данным» (хотя многие проверки — это часть бизнес-логики), и вот эта формулировка — очень спорна.
>Если автономный код принимает на вход неконтроллируемые значения, он должен их проверить. В противном случае проверять данные нет смысла, если вы пишете не космос, атом или медицину. Контроллер — это никак не автономный код, который принимает неконтроллируемые значения. А вот слой интерфейса — это именно оно.

То есть если кто-то другой пишет другой слой интерфейса, который не так строг ко входным данным, в результате чего контроллер летит к чертям из-за невалидных данных, то разработчик контроллера говорит «ну это вы сами виноваты, должны сами проверять, какие мне нужны данные». Получается, интерфейс должен знать, какие данные для контроллера являются валидными, а какие нет, я вас правильно понимаю?
Вообще, конечно, должен, это же логично. Но это не отменяет того, что контроллер не должен лететь к чертям, а должен вежливо объяснять, что не так.
>… контроллер не должен лететь к чертям, а должен вежливо объяснять, что не так.

То есть проверять данные? ;)
Входные данные для контроллера поставляется компонент, который их принимает от юзера. Если это форма — то это объект, который представляет эту форму. Если это список с фильтрами и сортировками — то это объект, представляющий список. При этом контроллер сам его инициализирует и запускает в работу. Еще вариант, что параметры проверяет на валидность роутер, когда речь о парсинге URL (ну вон как ID поста на хабре). Кстати роутер сам же и 404 должен отдать при ошибке, без участия контроллера. Когда ни формы, ни списка, ни роута как таковоого нет, проверка происходит в контроллере, потому что он становится точкой входа. Но это как бы относительно редко используется *ну прямая передача get-параметров из ссылки).
«Может лучше продолжать тестировать наш код в прямом эфире, во время того как пользователи взаимодействуют с нашим программным продуктом?»

Я думаю, лучше перевести эту фразу так:

«Я никогда не читал про Бертрана Мейера и Design-by-contract поэтому решил сделать свою реализацию смешивающую документацию, контракты и тест в одном понятии „утка“»
Кстати, порекомендуйте литературу от Мейера, пожалуйста.
Я читал про Design by contract миллиард лет назад и уже не помню какого автора, так что могу только порекомендовать поискать самостоятельно про Design by contract и язык Эйфель (кстати, DBC — это зарегистрированная торговая марка, поэтому MS, например, называет у себя тоже самое Code contracts)
Хм, а как же правило «не писать специальный код для тестов» в продакшене?
Кто нибудь знает, что делать с подобной информацией? ООП умерло, TDD умерла, DDD умерла, DI умер, XP умерло, Agile давно умер, SOLID умер, FP тоже умерло?

Только криворукие спагетти-программисты вечные! На них и уповаем.
Sign up to leave a comment.

Articles