пятница, января 30, 2009

The validation problem

Сложно найти программиста, который бы никогда не сталкивался с задачей проверки пользовательских данных. Буквально на первой же лабе в институте, преподаватель "ломает" программу некорректным вводом. Почти все через это прошли и признают, что относится к входным данным нужно со здоровой паранойей. Вопрос лишь в том, где именно проверять входные данные. Возбужденные сторонники ООП поднимают на щит инкапсуляцию и провозглашают немедленную валидацию на уровне классов бизнес-сущностей, бородатые DBA ратуют за проверки на уровне БД, очкастые архитекторы стоят на вынесении валидаторов в отдельную сущность, аппелируя к SRP. Разумеется, все они правы по-своему.

Есть такая штука, которая называется инвариантом системы. Это такой набор утверждений, истинных в любом ее состоянии. Хороший пример такого инварианта -- бухгалтерский баланс. Сумма активов равна сумме пассивов. Если это не так, значит где-то произошла серьезная ошибка. Для отдельных компонентов могут быть свои инварианты, попроще. Например, для любого счета всегда известна валюта или метод никогда не возвращает null. В первую очередь инварианты нужны внутри самой системы. Если мы знаем, что для всех счетов всегда известна валюта, мы можем обращаться к ней без проверки не рискуя получить NullPointerException. Кто же ответсвенен за консистентное состояние системы? Очевидно, сама система. Технически это можно сделать разными способами. Годятся простые проверки, вынос обязательных полей в конструкторы, констрейнты на базе, ассерты, современные средства контрактного программирования и все прочее, что придет в голову. Однако у инварианта есть side effect в том, что каждое дополнительное утверждение снижает гибкость системы. Если какое-то состояние системы нарушает инвариант, оно невозможно, независимо от желаний программиста. Избыточность в инварианте системы приводит к тому, что вместо простых действий устраиваются танцы вприсядку с целью обойти инвариант.

Чтобы избежать этой опасности, инвариант следует тщательно оберегать от распухания. Для того утверждения не влияющие на целостность системы целесообразно выделить в отдельный слой. Например, в системе никому не требуется номер паспорта клиента, но с точки зрения бизнеса это поле относится к обязательным, потому что по закону положено. Более того, часто возникают ситуации, когда в одних случаях поле является обязательным, а в других опциональным. Например, паспортные данные требуется от клиента клиент собирается получить деньги и небязательны если он принес деньги отдать.

Проверки, которые не входят в инвариант стоит собирать в одном месте, что значительно упрощает внесение изменений. Тут хорошо годятся и отдельные классы *Validator, валидаторы на основе XML правил и т.п. Если правила меняются неприлично часто, хорошо помогает вообще отдать настройку правил валидации админу. Пусть он в рантайме поднимает галочки. Пользователи будут довольны.

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

воскресенье, января 11, 2009

Chinese classification

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

  1. принадлежащих императору;
  2. бальзамированных;
  3. домашних;
  4. молочных поросят;
  5. сирен;
  6. сказочных;
  7. бродячих псов;
  8. включённых в эту классификацию;
  9. бешеных;
  10. бессчетных;
  11. нарисованных тончайшей кистью из верблюжьей шерсти;
  12. прочих;
  13. только что разбивших кувшин;
  14. издалека кажущихся мухами.

С точки зрения современного образованного человека китайская классификация выглядит дико. С другой стороны такие классификации встречаются повсеместно, достаточной вспомнить классификатор жанров FB2, библиотечный каталог, или классификатор МКБ-10. ailev вообще высказал мысль о том, что все онтологии -- это замаскированные китайские классификации, ибо именно таковые классификации лежат в основе мира, именно к таким классификациям привыкли люди. Если это так, возникает вопрос, откуда берутся "китайские классификации" и почему люди охотнее создают и пользуются ими вместо строгих таксономий?

Не смотря на кажущуюся сумбурность, "китайская классификация" подчинена определенной внутренней логике. Строгая таксономия делит мир на классы согласно некоторого рационального критерия: принадлежит животное императору или нет; домашнее оно или дикое; существует оно в реальности или же оно вымышленное и т.п. Для "китайской" классификации в качестве основания выступает не рациональный критерий а степень важности некоторого класса. В каноническом примере, создателя классификации равно интересуют, как животные императора, так и домашние животные, независимо от того, кому они принадлежат. Если бы автор пожелал создать на тех же критериях строгую рациональную классификацию, она получилась бы в несколько раз больше и многие ее классы оказались бы невостребованными. "Китайские классификации" стоит рассматривать как оптимизации строгих таксономий под конкретные способы использования.

Очевидно, что любую строгую иерархическую классификацицию можно сделать китайской. Достаточно присвоить классам разные веса и сгруппировать на одном уровне классы с одинаковым весом. Некоторый аналог такого приема в дизайне интерфейсов -- быстрые закладки для часто используемых функций. К сожалению, простого способа обратного преобразования не существует, поскольку невозможно автоматически выделить рациональные критерии из мешанины классов. Единственный достоверный способ на сегодня, это кропотливая ручная обработка. Неудивительно, что инициатива semantic web продвигается с таким скрипом. "Китайские" классификации это объективная часть природы человека, и хотим мы этого или нет, нам придется учиться с ними справляться.