История разработки модуля для хранения адресов. Часть 1
В этой истории я поведаю об одной из главных причин ухода программистов на фриланс. Эта история происходила в моем отделе. Для упрощения повествования, пусть у нас будет два действующих лица: Заказчик и Программист.
Начальная задача: Создать модуль для хранения адресов.
Часть 0. Вступление
Изначально у Заказчика была готовая система, написанная в 2010 году. При первичном утверждении нового проекта Заказчик одобрил старую структуру базы данных. Для хранения адресов использовалась следующая схема, причем таблицами выше «Населенный пункт» никто не пользовался (так как на тот момент Заказчик всю свою деятельность вел в одном городе).
Часть 1. «Лучше бы ты молчал…»
При программной реализации Программист посмотрел на связку Страна – Область – Районы – Населенный пункт
и задумался: «У нас ведь есть города, которые не входят в районы. Есть города, не принадлежащие ни одной области (например, Москва). Подобная иерархия не подходит». Об этих обстоятельствах было доложено Заказчику. И началось хождение по мукам. Наверное, в этот момент нужно было предложить избавиться от связей между Страны – Область – Районы, и сделать их справочными таблицами, примерно так:
Часть 2. «Стандарт это хорошо… но не всегда…»
Размышления Программиста по поводу правильности хранения адресов заставили глубоко задуматься Заказчика. В это время Программист решил найти проверенные решения, желательно по стандарту. КЛАДР был отвергнут сразу. А вот ОКАТО приглянулся. Сама структура ОКАТО хранит любую иерархию до населенного пункта, к тому же, в открытом доступе имеются готовые базы. Из более мелких изменений: было решено объединить все справочные таблицы в одну. Структура БД приняла следующий вид:
Часть 3. «А давайте всё хранить в одной таблице…»
Примерно в то же время Заказчик придумал «идеальную» схему для хранения всей структуры: объединить в одну таблицу и связать все через parent_id
. В его представлении все было шикарно, ведь можно было хранить любую иерархию от планеты до комнаты:
«Планета Земля – Россия – Тюменская область – ХМао – Нижневартовск – ул. Мира – д. 60 – кв. 10 – комната 1
».
Программисту потребовалось приложить немалые усилия, чтобы отговорить Заказчика от этой затеи.
Часть 4. «Если не в одной, то в четырех…»
Заказчик всё не хотел принимать версию с использованием ОКАТО, хотя и признал, что стандарты – это хорошо. При очередном мозговом штурме всплыла еще одна проблема: дома без улиц (в соседнем городе — Стрежевом, таких оказалось не мало).
Его следующей идеей было хранить адрес в четырёх таблицах: Территория – Населенный Пункт – Строение – Помещение
. В первой таблице мы сохраняем всю иерархию до города. Во второй – сам город. В третьей – дом (улицы, микрорайоны превратились в признаки дома). В четвертой – сами помещения. После небольшого обсуждения было принято решение добавить еще три таблицы с признаками и одну таблицу с описаниями-комментариями.
Часть 5. «Точно – признак?»
Проблемы были обнаружены в таблице Территория, иерархию которой предлагалось хранить через parent_id
. Вспомнили и про географические координаты. В итоге решили: Территорию хранить через nested sets, часто используемые признаки включить в сами таблицы (мкр, улицы).
Часть 6. «Где эта улица… Где этот дом…»
Промахом в последней версии был поиск. Ведь как мы обычно ищем адрес? Вводим город, улицу, дом… В нашей схеме, чтобы получить список улиц в городе, необходимо выбрать все дома города, и только потом получить список улиц. Поэтому было решено создать промежуточную таблицу «Улицы Населенного Пункта». Также из признаков помещения в основную таблицу были включены этаж и подъезд.
Эта схема была утверждена и разработка продолжилась. Таблицы в БД, Модели, Формы – всё уже было готово. Несколько раз утвердили интерфейс. И случился нежданчик… Продолжение следует…