Изменения

BugzillaORM

7398 байтов добавлено, 09:09, 24 июля 2012
м
Обновление модели
[[Категория:Разработка]]В Bugzilla половина кода в шаблонах, половина на основе полу-ORM’а Bugzilla::Object. Большая часть — говнокод. С одной стороны — ORM бы туда, было бы классно, НО! ORM мало, и нужен не он! Все (Почти все существующие) ORM-движки — движки (кроме разве что [https://docs.djangoproject.com/en/dev/topics/db/models/ Django Models]) — это просто объектный интерфейс к базе данных. А нужно некое объектное ядро, которое бы позволяло создавать свои объекты, с полями различных типов, в том числе и ссылающимися на другие такие же объекты, с возможностью приписывания специальных особенностей полюполям, с общим механизмом общими механизмами хранения истории , рассылки уведомлений, системой прав и с автоматическим базовым CRUD-интерфейсом. На самом деле, выше описан почти что [http://roundup.sourceforge.net/ Roundup], за теми исключениями, что он не умеет зависимые селекты (раз) и :)
== Идеи по созданию объектного ядра ==
=== Объекты в Bugzilla:=== 
* баг
* классификация, продукт, компонент
}
</graph>
 
Связь «многие ко многим» багов с ключевыми словами можно разбить на две «один ко многим» (тег &rarr; тег бага &larr; баг).
Причём, понятное дело, если баг принадлежит к некоторому продукту (через компонент), то и его версия, milestone, agreement должны принадлежать к тому же продукту. Сейчас в Bugzilla это реализуется так — для каждой сущности, связанной с багом, в баге есть «поле», а для ограничения значений полей поля делаются «зависимыми» от других полей. Из-за этого там куча костылей и, по сути, повесить зависимость на отличное от поля «продукт» поле невозможно.
А подумав и посмотрев на красивую картинку выше, можно прийти к другой идее=== Минусы текущей реализации === Чем плоха текущая багзильная реализация этого «добра»? Очень просто: сущности'''почти ни хрена не настраивается''' - нельзя ни добавить свои возможности, связи между ними ни отрубить ненужные встроенные. Ибо всё жёстко и идея непротиворечивого состояния криво (если всё это «замкнуть»хардкод). Но во-первых, это только часть картины, ибо на это А ещё навёрнуты:; Несколько ссылок на один тип: Всё это ведь не означает, что баг должен иметь * История хранится только одну ссылку, скажем, на версию. Он вполне может иметь две ссылки — например, версия, в которой нашли и версия, в которой зафиксили. Последняя — это, по сути, target milestoneдля багов, но ведь это не значит, что мы не можем захотеть ссылаться на сущность того же типа «версия»для остальных объектов. Или другой пример: двухуровневая техподдержка, ссылка на связанный внешний баг и ссылка на связанный внешний продукт из продукта. В конечном итоге, это можно решить присвоением «имени» ссылке, по умолчанию равному названию типа сущности, на которую ссылаемся. Это, кстати, снова становится похоже на схему с зависимыми полями :); Права: Сейчас в Bugzilla они рулятся на уровне продукта* Шаблоны переусложнены. TODO; Скрытие/показ полей бага в зависимости друг от друга: Сейчас в Bugzilla это реализовано отдельно от функционала контроля значений — по сути* Нет "объектов", скрываться выпадающее поле может в зависимости от одного поля, а набор значений может при этом меняться в зависимости от другого. А на самом деле '''''это неправильно'''''! Что за бред — поле скрыто, но при этом есть варианты«значения полей», которые можно выбрать? Или наоборот — поле доступносоответсвенно, но из вариантов — только пустое значение. Не подходит. Соответственно, контроль показа поля в том виде, в котором он есть в Bugzilla сейчас, актуален только для полей других типов — строковых им не добавишь атрибутов и так далее.; Email-уведомления об изменениях: С ними более-менее всё понятно. По сути, они всегда привязываются к какому-либо полю какого-либо объекта общей структуры, ссылающемуся на пользователя/пользователей (например, Assignee и CC бага) — это со стороны ссылок на пользователей. Вторая сторона — событие, но единственно возможные события — изменение поля или создание новой сущностине навесишь логики.
А во-вторых — если не хранить поле (например, продукт), от которого зависит другое поле (например, компонент), в самом баге, тоже полезут костыли (только другие). Соответственно, нужно понять, чем вообще схема, реализованная в самой багзилле сейчас, плоха? А вот чем:
* Значения кастом полей в таблице багов хранятся не ссылками по ID, а по именам, что создаёт геморрой для зависимых полей, так как чтобы точно идентифицировать значение, приходится брать ещё и значение поля, от которого оно зависит.
* «Поле» (селект и мультиселект) совмещено с объектом, соответственно, не добавишь дополнительных атрибутов объекту.* Для выпадающих списков есть как «контроль значений», так и «контроль видимости поля», что в корне '''''неверно (см. выше)'''''! Типа поле скрыто, но при этом есть варианты, которые можно выбрать? Бред! Или наоборот — поле доступно, но из вариантов — только пустое значение.
* По факту, ни от чего, кроме продукта, зависимым значение не сделаешь.
* История хранится только для багов, но не для остальных объектов.* Поля Код полей не генерятся генерится автоматически, а ручками вписываются в шаблоны.* На всё это навёрнута туча неструктурированного кода, определяющего поведение «встроенных» полей.
Учитывая, что всё равно нужно вычислять «непротиворечивость» зависимостей полей, появляется следующая мысль:* Разделяем «поля» и «объекты».* Объекты могут содержат ссылки на другие (компонент &larr; продукт).* Поле содержит ссылку на другое поле, в которое должна попадать ссылка на объект, на который ссылается объект, на который ссылается поле +))=== Проект супер-объектного-ядра ===
Но тут появляется следующий вопросЧто предлагается сделать: это что* Есть объекты. У объектов есть поля (разных типов). В том числе, всегда во все есть типы «multi-select» и «single-select», ссылающиеся на другие объекты тащить все связи .* Зависимости полей могут прописываться дополнительно, в виде ограничений вида: «баг.компонент.продукт == баг.продукт». Могут и не прописываться. Теоретически, могут прописываться несколько ограничений на одно поле, например, чтобы какой-нибудь атрибут зависел и от продукта, и от, скажем, операционной системы. Такое устройство наиболее гибкое и в частности позволяет багу иметь несколько полей, ссылающихся на один тип объектов.* Поля могут скрываться в зависимости от значений других полей. Селект-поля скрываются, с которыми они связаны если в них по зависимостям нечего выбирать. На поля остальных типов можно вешать «настройку видимости», подобную текущей багзильной реализации — просто тупо «поле = одно из значений…».* HTML-код полей должен генерироваться автоматически. Также желательна возможность задавать группировку полей в интерфейсе — например, опционально раскрываемые «Advanced Fields» («замыкать»только общим fieldset’ом, а не как сейчас — просто скрытие полей в разных местах формы)? No way.* На поля можно назначить дополнительные обработчики, задающие более хитрое поведение. Сами обработчики пишутся в коде, по возможности — максимально абстрагированно от конкретного поля. Назначаться они при этом должны не из кода, а из интерфейса конфигурации модели. На этих дополнительных обработчиках должно работать всё! А чо делать?Примеры:** Платформа, ОС: функции угадывания значения по умолчанию на основе заголовков запроса.** Статус: есть ограничения переходов из состояния в состояние (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 — первичный ключТипы объектов** Название типа** Дополнительное поведение типа
* Поля
** Ссылка на родителя объект** 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]])