Изменения

BugzillaORM

13 456 байтов добавлено, 09:09, 24 июля 2012
м
Обновление модели
[[Категория:Разработка]]В Bugzilla половина кода в шаблонах, половина на основе полу-ORM’а Bugzilla::Object. Большая часть — говнокод. С одной стороны — ORM бы туда, было бы классно, НО! ORM мало, и нужен не он! Все (Почти все существующие) ORM-движки — движки (кроме разве что [https://docs.djangoproject.com/en/dev/topics/db/models/ Django Models]) — это просто объектный интерфейс к базе данных. А нужно некое объектное ядро, которое бы позволяло создавать свои объекты, с полями различных типов, в том числе и ссылающимися на другие такие же объекты, с возможностью приписывания специальных особенностей полюполям, с общим механизмом общими механизмами хранения истории , рассылки уведомлений, системой прав и с автоматическим базовым CRUD-интерфейсом. == Идеи по созданию объектного ядра == === Объекты в Bugzilla ===
Объекты в Bugzilla:
* баг
* классификация, продукт, компонент
Причём, понятное дело, если баг принадлежит к некоторому продукту (через компонент), то и его версия, milestone, agreement должны принадлежать к тому же продукту. Сейчас в Bugzilla это реализуется так — для каждой сущности, связанной с багом, в баге есть «поле», а для ограничения значений полей поля делаются «зависимыми» от других полей. Из-за этого там куча костылей и, по сути, повесить зависимость на отличное от поля «продукт» поле невозможно.
А подумав и посмотрев на красивую картинку выше, мы приходим к другой идее — '''есть сущности, связи между ними и идея непротиворечивого состояния'''. Но это только часть картины, ибо на это ещё навёрнуты:* Права (в Bugzilla рулятся на уровне продукта)* Скрытие/показ полей бага в зависимости друг от друга* Email-уведомления об изменениях=== Минусы текущей реализации ===
== Текущее состояние ==Чем плоха текущая багзильная реализация этого «добра»?
Базовые (то, чего не быть логически Очень просто: '''почти ни хрена не можетнастраивается''' - нельзя ни добавить свои возможности, ни отрубить ненужные встроенные. Ибо всё жёстко и криво (хардкод). А ещё:* ОбъектИстория хранится только для багов, баг, пользователь, группа, комментарий к багуно не для остальных объектов.* Продукт имеет специальный смысл — разграничение правШаблоны переусложнены. Поэтому он тоже обязателен* Нет "объектов", есть «значения полей», соответсвенно, им не добавишь атрибутов и не навесишь логики.
* Значения кастом полей в таблице багов хранятся не ссылками по ID, а по именам, что создаёт геморрой для зависимых полей, так как чтобы точно идентифицировать значение, приходится брать ещё и значение поля, от которого оно зависит.* Для выпадающих списков есть как «контроль значений», так и «контроль видимости поля», что в корне '''''неверно'''''! Типа поле скрыто, но при этом есть варианты, которые можно выбрать? Бред! Или наоборот — поле доступно, но из вариантов — только пустое значение.* По факту, ни от чего, кроме продукта, зависимым значение не сделаешь.* Код полей не генерится автоматически, а ручками вписываются в шаблоны.* На всё это навёрнута туча неструктурированного кода, определяющего поведение «встроенных» полей. === Проект супер-объектного-ядра === Что предлагается сделать:* Есть объекты. У объектов естьполя (разных типов). В том числе, есть типы «multi-select» и «single-select», ссылающиеся на другие объекты.* Зависимости полей могут прописываться дополнительно, в виде ограничений вида:«баг.компонент.продукт == баг.продукт». Могут и не прописываться. Теоретически, могут прописываться несколько ограничений на одно поле, например, чтобы какой-нибудь атрибут зависел и от продукта, и от, скажем, операционной системы. Такое устройство наиболее гибкое и в частности позволяет багу иметь несколько полей, ссылающихся на один тип объектов.* ID — первичный ключПоля могут скрываться в зависимости от значений других полей. Селект-поля скрываются, если в них по зависимостям нечего выбирать. На поля остальных типов можно вешать «настройку видимости», подобную текущей багзильной реализации — просто тупо «поле = одно из значений…».* HTML-код полей должен генерироваться автоматически. Также желательна возможность задавать группировку полей в интерфейсе — например, опционально раскрываемые «Advanced Fields» (только общим fieldset’ом, а не как сейчас — просто скрытие полей в разных местах формы).* На поля можно назначить дополнительные обработчики, задающие более хитрое поведение. Сами обработчики пишутся в коде, по возможности — максимально абстрагированно от конкретного поля. Назначаться они при этом должны не из кода, а из интерфейса конфигурации модели. На этих дополнительных обработчиках должно работать всё! Примеры:** Платформа, ОС: функции угадывания значения по умолчанию на основе заголовков запроса.** Статус: есть ограничения переходов из состояния в состояние (workflow). Возможно, его нужно попытаться вынести в базовые настройки модели.** CC: специальное поведение при клонировании, смене Assignee и QA (старые добавляются в CC), специальное «значение по умолчанию», зависящее от компонента. Возможно, зависимые значения по умолчанию стоит как-то протащить в общее ядро, но это чуть более тонкий момент, чем всё остальное.** Keywords/теги: автосоздание новых значений.* История хранится централизованно для всех объектов.* Общий механизм рассылки изменений по почте для всех объектов каким-либо образом «связанным» пользователям. Настройки уведомлений на уровнях: событие (изменено значение поля, добавлена сущность) и отношение (собственно связь).* Поиск: адаптировать сильно прокачанный движок поиска из [http://wiki.4intra.net/Bugzilla4Intranet Bugzilla4Intranet]. Адаптировать долго не придётся, потому что с точки зрения read-only все типы полей останутся, по сути, те же самые. С другой стороны, его нужно обобщить, так что кое-что сделать всё-таки будет нужно. Но зато в итоге получится супер-инструмент — система выборок, которая отлично хавает большие базы, сложные ''и произвольные'' структуры запросов и не давится :) (доказано Bugzilla4Intranet)* Права доступа: Нужна опять-таки общая схема для всех объектов, с одной стороны, простая для вычисления системой, а с другой стороны, дающая достаточную гибкость разных настроек. По всей видимости, нужны с одной стороны опять-таки «связанные» пользователи, а с другой стороны — роли. Причём, пользователи могут быть «связанные» через какое-то поле — например, человек может быть связан с багом, потому что прописан как Global Watcher для продукта этого бага. Роли могут набираться из действий над полями различных объектов и права на просмотр объектов. Возможно, нужно давать возможность разграничивать доступ на просмотр к разным полям — например, в Bugzilla только группа time-tracker’ов может посмотреть информацию о рабочем времени. Таким образом наш трекер превратится, по сути, в модульное приложение, построенное вокруг очень прокачанного автоинтерфейса полей и объектов. Естественно, это уже не Bugzilla ни разу, но зато чем-то похоже на [http://roundup.sourceforge.net/ Roundup] — «конструктор трекеров». Однако и с ним различий много — roundup не умеет зависимых селект-полей, модель задаётся в коде, права доступа слабые, поиск слабый. === Обновление модели === Обновление базы багзильское (тупая последовательность операций):* (+) Очевидный порядок обновлений, нет проблем с их зависимостями друг от друга (новые просто дописываются в конец, порядок всегда правильный)* (-) Не проверяется, корректна ли схема БД после обновлений* (-) Обновления задаются именно для SQL БД, а не для метамодели* (-) Не очень красивая портянка в функции обновления БД Обновление базы наше:* AddType -> RenameFields -> AddFields -> ChangeFields -> DropFields* ChangeFields с помощью функций обновления* (???) Самый интересный вопрос - как сделать функции обновления не на SQL, в условиях когда модель в неконсистентном и вообще не знает, в каком состоянии?* После каждого шага запуск хука* Переименования задаются декларативно* Возможность Dry Run, просмотра и проверки последовательности обновлений* Зависимости обновлений в рамках каждого шага можно задать декларативно (хотя ситуация редкая)*: А может, просто стоит задавать их в ассоциативном массиве по порядку* Ещё может быть, что обновление одного типа зависит от обновления другого (причём это уже более частая ситуация) === Модель === Получается, что ядро модели состоит из следующих таблиц:* Типы объектов** Название типа** Дополнительное поведение типа
* Поля
** Ссылка на родителя объект** ID поля** Название поля** Тип поля** Nullable? Т.е. разрешено ли пустое значение** Поле этого же объекта, контролирующее видимость данного (для не-select полей)** Связи поля (для select-полей)** Дополнительное поведение поля* Контроль видимости полей** Ссылка на поле** IDобъекта, для которого оно видно* Транзакции (группы изменений)** Момент времени** Изменивший пользователь* История изменений** Ссылка на транзакцию** Тип объекта** Ссылка на объект** Ссылка на поле (кроме добавления объекта)** Старое значение** Новое значение* Один неудаляемый тип задаётся в классе сущности— пользователи (их поля, тем не менее, можно менять). Сущности образуют дерево.* Способ преобразования в строкуСвязи объектов с пользователями** ID связи** Название связи** Ссылка на объект** Цепочка свойств, заканчивающаяся объектом «пользователь»* Пользовательские настройки оповещений** Ссылка на пользователя (либо пустая для настроек по умолчанию)** Ссылка на связь** Тип события: добавление/удаление/изменение** Ссылка на поле объекта (может быть пустая)* Роли (или группы, что примерно то же самое)** Включаемые роли** Включаемые разрешения* Разрешения (из которых состоят роли)** Ссылка на связь** Тип разрешения: просмотр/создание/удаление/изменение** Ссылка на поле объекта (пустая = весь объект)** Ссылка на значение поля (пустая = любое)
Логическая неконсистентность:* Объект «компонент» имеет поле «продукт», тип которого — ссылка на объект «продукт»* Чтобы отказаться от дурацкой системы «контролирующих значений» и сделать дерево, в объекте «баг» самостоятельного поля «продукт» быть не должно* Но как тогда выбирать сначала продукт, а потом компонент, при редактировании бага?* Получается, что «продукт» — это просто способ подразделения компонентов=== Типы полей ===
Ещё одна логическая неконсистентность:<tab sep="bar" class="wikitable" head="top">* Если мы не хотим завязываться на существование поля «компонент»Тип | Параметры | ПредставленияСтрока | Длина | Input, но у нас всё равно «дерево»textarea, получаетсяrich editЛогический | | ФлажокЧисловой | Точность (M.N) | InputДата и/или время | Дата? Время? | Поле со всплывающим календарём, что в случае отсутствия поля «компонент» баг привязывается напрямую к продуктупросто календарь, просто полеФайл | | Поле загрузки файлаSingle-select | Тип объекта | Радиобатон, HTML-селектMulti-select | Тип объекта | HTML-мультиселект, флажки, комбо-бокс</tab>
И ещё одна== Текущее состояние == Базовые поля (то, чего не быть логически не может):* Если «продукт» — это всего лишь способ уточнения компонентовОбъект, то как же ограничивать им другие поля?баг, пользователь, группа, комментарий к багу.* Продукт имеет специальный смысл — разграничение прав. Поэтому он тоже обязателен.
У каждого поля есть:
** Два способа показа — поле со списком (комбобокс), или мультиселект
* Список тегов, с автодобавлением значений
 
Что ушло бы в этот типа ORM ?
 
* Custom Fields, то есть, управление полями багов.
* Отключение стандартных полей типа OS, Hardware.
* Добавление спецполей в продукты, компоненты и т. д. — сейчас это делается в коде.
* Версионирование всех объектов. История бы хранилась унифицированно. Не было бы отдельно таблиц bugs_activity и longdescs, соответственно не было бы и тормозов при проверке «Only bugs changed between…» либо комментарии бы дублировались в bugs_activity (логичнее)
* Простые интерфейсы типа CRUD (Create/Read/Update/Delete), сейчас созданные непонятно каким копипастом. В основном имеется ввиду админка.
* Права на редактирование объектов.
* Валидаторы и подсказки значений.
* Корректная валидация зависимостей полей друг от друга.
* Часть SQL-запросов, написанных ручками в коде.
* Вся логика постановки/обновления багов из process_bug и post_bug, дублированная сейчас в обработке входящих e-mailов и Excel-импорте
* Даже Excel- и XML-импорт, причём импортировать можно было бы вообще всё что угодно.
 
Появились бы дополнительные возможности:
 
* Создание новых объектов типа SCRUM карточек.
* Изменение типов стандартных полей типа целочисленных приоритетов.
* Можно было бы прикрутить статистику по любым объектам, причём с Time Machine, то есть просмотром статистики за любой прошедший момент времени. :)
== Существующие поля ==
** Canconfirm
** Editbugs
* Private комментарии — комментарии — видны только инсайдер-группе* Информация о таймтрекинге — таймтрекинге — видна только группе, списывающей время
* reporter_accessible, cclist_accessible на отдельных багах
* Опциональные группы на отдельных багах
* Права editclassifications, editcomponents, editfields, editkeywords, editusers
== Хорошо бы рефакторить = Настройки оповещений о багах ===
Отношения:* Assignee, QA, Reporter, CC* Requestee или Setter флага (реально в Bugzilla прикручено сильно сбоку)* По идее — также создатель аттачмента, коммента (если разрешать править)* Watcher указанного выше* Global Watcher События:* Добавлен/удалён из указанного выше* Изменено одно из полей бага (м.б отдельные настройки, м.б вместе)* Баг / блокирующий баг меняет статус с закрытого на открытый или обратно* «Но кроме» UNCONFIRMED* «Но кроме» своих изменений == Что не так? == Что в Bugzilla не так? Что нужно рефакторитьпоменять, чтобы багзилла она перестала быть говном? Да, я знаю, что почти всё, но дело не в этом — дело в том, что создавать систему «от противного» — есть хороший тон, ведущий к прогрессу. === Ядро === Самое жирное «не так» в Bugzilla — это слабость ядра. Если бы ядро было прокачанным, как в начале статьи, оно бы заменило: * Custom Fields, то есть, управление полями багов.* Отключение стандартных полей типа OS, Hardware.* Добавление спецполей в продукты, компоненты и т. д. — сейчас это делается в коде.* Версионирование всех объектов. История бы хранилась унифицированно. Не было бы отдельно таблиц bugs_activity и longdescs, соответственно не было бы и тормозов при проверке «Only bugs changed between…» либо комментарии бы дублировались в bugs_activity (логичнее)* Отправка почты, которая сейчас отправляется через 2 разных места.* Простые интерфейсы типа CRUD (Create/Read/Update/Delete), сейчас созданные непонятно каким копипастом. В основном имеется ввиду админка.* Система прав стала бы и проще (по сравнению с хрен-пойми-системой Mandatory/Default/Shown/NA), и имела бы больше возможностей.* Валидаторы и подсказки значений.* Корректная валидация зависимостей полей друг от друга.* Часть SQL-запросов, написанных ручками в коде.* Вся логика постановки/обновления багов из process_bug и post_bug, дублированная сейчас в обработке входящих e-mailов и Excel-импорте* Даже Excel- и XML-импорт, причём импортировать можно было бы вообще всё что угодно. Появились бы дополнительные возможности: * Создание новых объектов типа SCRUM карточек.* Изменение типов стандартных полей типа целочисленных приоритетов.* Можно было бы прикрутить статистику по любым объектам, причём с Time Machine, то есть просмотром статистики за любой прошедший момент времени. :)
=== Внешности ===
* Большая часть интерфейсов нуждается в полной переделке. Например:** На форме бага «Show Advanced Fields» должно быть сделано отдельной группкой полей (fieldset), а не скрытием полей прямо посреди формы в разных местах (пугает).** Страница настройки прав продукта — мегастрёмная. Таблица с группами там на хрен не нужна никому вообще.** Частично относится к ядру, но — интерфейс редактирования «контроля значений» кастом-полей это сейчас полная жесть — например, нельзя посмотреть список значений кастом поля для конкретного продукта (от которого зависят наборы значений).* Историю изменений бага показывать прямо внутри комментов вперемешку с комментариями к багу (как в trac, кстатиа-ля Trac). Туда же можно заинтегрировать и замешать коммиты из системы контроля версий.* Добавить ленту обновлений по багам, поиск «последних багов», что-то типа форум-функциональности.* Добавить гридВозможно, добавить Grid View с возможностью массовых обновлений в поиске.* Необязательно — Отрефакторить кучу действий, связанных с поиском, расположенных внизу, можно на вики-манер превратить во вкладочкипод списком багов.* keywords Keywords переделать в «теги», то есть, сделать, чтобы они сами заводились новые.* <s>Заменить YUI на jQuery</s> в Bugzilla4Intranet уже, форму поиска сгруппировать (но не так, как в 4.0), сделать почти все фильтры добавляемыми, добавляемыми через JS, чтобы не перезагружалась страница каждый раз* Механизм «ограничения показа»… кастом-полей переделать в древовидную структуру* Переделать систему прав:*: Сейчас продукт задаёт, по сути, КНФ («группа = юзеры + набор групп; продукт = & групп»), а задавать тупо доступ ОДНОЙ группой. А группа может быть либо пересечением N других, либо объединением N других + юзеров. Причина: пересечение в реальности используется ОЧЕНЬ редко.*: Соответственно все включения в группы сделать, чтобы материализовывались и чтобы вычислять каждый раз вычислять замыкания по наборам групп было не нужно. Это упростит и ускорит ВСЁ, в первую очередь фильтрацию.* Документацию «насытить» в вики, POD-документацию по коду туда же.
=== Кишки , кроме ядра ===
* Историю изменений по багам хранить в общей таблице с комментариями. История по другим объектам тоже хранить там же. То есть нужен такой вот общий метод хранения истории по всем сущностям.
* Переписать код отправки почты, во-первых так чтобы отправлялась она через одно место, а не через 2 (в оригинале 3) разных, во-вторых чтобы параметры формировались не через жопу.
* Добавить глобальный объект статуса, в который сохранять почту, которую нужно отправить, и сообщения, которые сейчас руками сохраняются в сессию.
* Использовать не CGI, а хеши параметров запроса, это улучшает и производительность, и переносимость, и спасает от кучи глюков, так как например, $cgi->param может вернуть как список, так и скаляр
* Использовать не кучу CGI-скриптов, а несколько (мало) точек входа и классы, всю мохнатую логику перенести в них. Не использовать модуль CGI.pm вообще (!), потому что он прости господи даже без use strict написан и порождает некоторые глюки сам по себе. В крайней форме точки доступа — доступа — это один index.cgi, позволяющий работать через CGI, один server.fcgi (FastCGI), один модуль для апача, и м.б. один для HTTP::Server::Simple. Ибо по сути, интерфейс «запроса» тривиален и не требует никакого бешеного CGI.* Прокачать объектное ядро, чтобы 90 % полей настраивались / отключались + см. начало статьи типа ORM.* Убрать ВСЕ строки (terms и ти т. п п.) и описания ошибок из шаблонов и «длинного if’а», добавить отдельный уровень «локализации» / «таблицы строк», и переместить всё это в него. Потенциально также переместить туда же вообще все строки/тексты из шаблонов, для лёгкой локализации.* Обязательно оставить совместимость с PostgreSQL, но генерилка запросов не должна на это рассчитывать и должна работать оптимальнее, чем сейчас, например, в смысле дурацких подзапросов assigned_to=(select id from profiles where login_name=?) и ти т. п п.* Желательно заменить Template::Toolkit на что-нибудь, хотя бы даже на моё поделие VMX::Template, чтобы не общаться с этим тормозом. Но как МИНИМУМ, даже если не заменять — заменять — убрать ВСЮ обратную связь с БД из шаблонов, ибо именно она убивает производительность в первую очередь! Ну ладно, не в первую, а во вторую, после дурацкого движка поиска. [[КатегорияХотя это и будет уже не MVC, а MVP :Bugzilla]])